├── Behavioral ├── Observer │ ├── new │ │ ├── Observer.cpp │ │ ├── SaferObservable.cpp │ │ ├── Observable.cpp │ │ ├── Observer.hpp │ │ ├── Observable.hpp │ │ ├── headers.hpp │ │ └── SaferObservable.hpp │ ├── Observer.vcxproj.user │ ├── Observer.vcxproj.filters │ ├── observer3.cpp │ ├── observer1.cpp │ ├── ObserverCodingExercise.cpp │ ├── observer2.cpp │ └── observer_book.cpp ├── Mediator │ ├── packages.config │ ├── Mediator.vcxproj.user │ ├── chatroom.h │ ├── chat.cpp │ ├── person.cpp │ ├── person.h │ ├── chatroom.cpp │ ├── Mediator.vcxproj.filters │ ├── MediatorCodingExercise.cpp │ └── soccer.cpp ├── Iterator │ ├── packages.config │ ├── Iterator.vcxproj.user │ ├── Iterator.vcxproj.filters │ ├── facade.cpp │ └── IteratorCodingExercise.cpp ├── State │ ├── State.vcxproj.user │ ├── State.vcxproj.filters │ ├── classic.cpp │ ├── StateCodingExercise.cpp │ ├── msm.cpp │ └── handmade.cpp ├── Command │ ├── Command.vcxproj.user │ ├── Command.vcxproj.filters │ ├── CommandCodingExercise.cpp │ ├── command_undo.cpp │ └── command.cpp ├── Memento │ ├── Memento.vcxproj.user │ ├── Memento.vcxproj.filters │ ├── MementoCodingExercise.cpp │ └── memento.cpp ├── Strategy │ ├── Strategy.vcxproj.user │ ├── Strategy.vcxproj.filters │ ├── strategy_static.cpp │ ├── strategy_dynamic.cpp │ └── StrategyCodingExercise.cpp ├── Visitor │ ├── Visitor.vcxproj.user │ ├── visitor.hpp │ ├── Visitor.vcxproj.filters │ ├── std_visit.cpp │ ├── visitor_intrusive.cpp │ ├── visitor_reflective.cpp │ ├── multimethods.cpp │ ├── model.hpp │ ├── visitor_acyclic.cpp │ ├── VisitorCodingExercise.cpp │ ├── single_double.cpp │ └── visitor.cpp ├── Interpreter │ ├── Interpreter.vcxproj.user │ ├── Interpreter.vcxproj.filters │ └── InterpreterCodingExercise.cpp ├── NullObject │ ├── NullObject.vcxproj.user │ ├── NullObject.vcxproj.filters │ └── null_object.cpp ├── TemplateMethod │ ├── TemplateMethod.vcxproj.user │ ├── TemplateMethod.vcxproj.filters │ ├── template_method.cpp │ └── TemplateMethodCodingExercise.cpp └── ChainOfResponsibility │ ├── ChainOfResponsibility.vcxproj.user │ ├── ChainOfResponsibility.vcxproj.filters │ ├── cor_broker.cpp │ ├── cor_pointer.cpp │ └── CoRCodingExercise.cpp ├── .gitattributes ├── Creational ├── Creational │ ├── FactoryExercise.h │ ├── Person.cpp │ ├── HotDrinkFactory.h │ ├── Creational.vcxproj.user │ ├── TeaFactory.h │ ├── Monostate.cpp │ ├── capitals.txt │ ├── CoffeeFactory.h │ ├── PersonBuilder.cpp │ ├── Facets.cpp │ ├── HotDrink.h │ ├── AbstractFactory.cpp │ ├── PersonAddressBuilder.h │ ├── PersonJobBuilder.h │ ├── PersonBuilder.h │ ├── Factory.cpp │ ├── BoostDIDemo.hpp │ ├── SingletonTests.cpp │ ├── FactoryCodingExercise.cpp │ ├── SingletonCodingExercise.cpp │ ├── FactoryMethod.cpp │ ├── DrinkFactory.h │ ├── InnerFactory.cpp │ ├── SRP.cpp │ ├── PrototypeCodingExercise.cpp │ ├── ISP.cpp │ ├── LSP.cpp │ ├── BoostDI.cpp │ ├── MaybeMonad.cpp │ ├── Person.h │ ├── GroovyStyle.cpp │ ├── Serialization.cpp │ ├── DIP.cpp │ ├── Singleton.h │ ├── Builder.cpp │ └── BuilderCodingExercise.cpp ├── Creational.tss └── Creational.sln ├── Structural ├── Proxy │ ├── .vscode │ │ └── .browse.VC.db │ ├── Proxy.vcxproj.user │ ├── packages.config │ ├── Proxy.vcxproj.filters │ └── ProxyCodingExercise.cpp ├── Adapter │ ├── .vs │ │ └── Adapter │ │ │ └── v14 │ │ │ └── .suo │ ├── Adapter.vcxproj.user │ ├── Adapter.vcxproj.filters │ ├── AdapterCodingExercise.cpp │ └── adapter.cpp ├── AdapterVisual │ ├── AdapterVisual.aps │ ├── AdapterVisual.rc │ ├── res │ │ ├── AdapterVisual.ico │ │ └── AdapterVisual.rc2 │ ├── AdapterVisual.vcxproj.user │ ├── stdafx.cpp │ ├── targetver.h │ ├── Resource.h │ ├── AdapterVisual.h │ ├── AdapterVisualDlg.h │ ├── Geometry.h │ ├── stdafx.h │ ├── AdapterVisual.vcxproj.filters │ └── AdapterVisual.cpp ├── Flyweight │ ├── .vscode │ │ └── .browse.VC.db │ ├── Flyweight.vcxproj.user │ ├── Flyweight.vcxproj.filters │ ├── FlyweightCodingExercise.cpp │ ├── capitalize.cpp │ └── flyweight.cpp ├── NullObject │ ├── .vscode │ │ └── .browse.VC.db │ ├── NullObject.vcxproj.user │ ├── NullObject.vcxproj.filters │ └── nullobject.cpp ├── Bridge │ ├── Bridge.vcxproj.user │ ├── Person.cpp │ ├── Person.h │ ├── Bridge.vcxproj.filters │ ├── BridgeCodingExercise.cpp │ └── bridge.cpp ├── Façade │ ├── Façade.vcxproj.user │ ├── Façade.vcxproj.filters │ ├── Bloom.cpp │ └── Console.h ├── Composite │ ├── Composite.vcxproj.user │ ├── Composite.vcxproj.filters │ ├── graphics.h │ ├── CompositeCodingExercise.cpp │ ├── composite.cpp │ ├── ArrayBackedProps.cpp │ └── neurons.cpp ├── Decorator │ ├── Decorator.vcxproj.user │ ├── Decorator.vcxproj.filters │ └── DecoratorCodingExercise.cpp └── PingPongService │ ├── appsettings.json │ ├── wwwroot │ └── web.config │ ├── Properties │ └── launchSettings.json │ ├── Controllers │ └── PingPongController.cs │ ├── PingPongService.csproj │ └── Startup.cs ├── README.md ├── Contributing.md └── LICENSE.txt /Behavioral/Observer/new/Observer.cpp: -------------------------------------------------------------------------------- 1 | #include "Observer.hpp" 2 | -------------------------------------------------------------------------------- /Behavioral/Observer/new/SaferObservable.cpp: -------------------------------------------------------------------------------- 1 | #include "SaferObservable.hpp" 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Behavioral/Observer/new/Observable.cpp: -------------------------------------------------------------------------------- 1 | #include "Observer.hpp" 2 | #include "Observable.hpp" 3 | -------------------------------------------------------------------------------- /Creational/Creational/FactoryExercise.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class FactoryExercise 4 | { 5 | public: 6 | 7 | }; 8 | -------------------------------------------------------------------------------- /Structural/Proxy/.vscode/.browse.VC.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/design-patterns-in-modern-cpp/HEAD/Structural/Proxy/.vscode/.browse.VC.db -------------------------------------------------------------------------------- /Structural/Adapter/.vs/Adapter/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/design-patterns-in-modern-cpp/HEAD/Structural/Adapter/.vs/Adapter/v14/.suo -------------------------------------------------------------------------------- /Structural/AdapterVisual/AdapterVisual.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/design-patterns-in-modern-cpp/HEAD/Structural/AdapterVisual/AdapterVisual.aps -------------------------------------------------------------------------------- /Structural/AdapterVisual/AdapterVisual.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/design-patterns-in-modern-cpp/HEAD/Structural/AdapterVisual/AdapterVisual.rc -------------------------------------------------------------------------------- /Structural/Flyweight/.vscode/.browse.VC.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/design-patterns-in-modern-cpp/HEAD/Structural/Flyweight/.vscode/.browse.VC.db -------------------------------------------------------------------------------- /Structural/NullObject/.vscode/.browse.VC.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/design-patterns-in-modern-cpp/HEAD/Structural/NullObject/.vscode/.browse.VC.db -------------------------------------------------------------------------------- /Creational/Creational/Person.cpp: -------------------------------------------------------------------------------- 1 | #include "Person.h" 2 | #include "PersonBuilder.h" 3 | 4 | PersonBuilder Person::create() 5 | { 6 | return PersonBuilder{}; 7 | } -------------------------------------------------------------------------------- /Structural/AdapterVisual/res/AdapterVisual.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/design-patterns-in-modern-cpp/HEAD/Structural/AdapterVisual/res/AdapterVisual.ico -------------------------------------------------------------------------------- /Structural/AdapterVisual/res/AdapterVisual.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/design-patterns-in-modern-cpp/HEAD/Structural/AdapterVisual/res/AdapterVisual.rc2 -------------------------------------------------------------------------------- /Behavioral/Mediator/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Creational/Creational/HotDrinkFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "HotDrink.h" 3 | 4 | struct HotDrinkFactory 5 | { 6 | virtual unique_ptr make() const = 0; 7 | }; -------------------------------------------------------------------------------- /Behavioral/Iterator/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/State/State.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/Bridge/Bridge.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/Façade/Façade.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/Proxy/Proxy.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/Command/Command.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/Iterator/Iterator.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/Mediator/Mediator.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/Memento/Memento.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/Observer/Observer.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/Strategy/Strategy.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/Visitor/Visitor.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/Adapter/Adapter.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/Interpreter/Interpreter.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/NullObject/NullObject.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Creational/Creational/Creational.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/Composite/Composite.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/Decorator/Decorator.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/Flyweight/Flyweight.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/NullObject/NullObject.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/AdapterVisual/AdapterVisual.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Behavioral/TemplateMethod/TemplateMethod.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Creational/Creational/TeaFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "HotDrinkFactory.h" 3 | 4 | struct TeaFactory : HotDrinkFactory 5 | { 6 | unique_ptr make() const override { 7 | return make_unique(); 8 | } 9 | }; -------------------------------------------------------------------------------- /Behavioral/ChainOfResponsibility/ChainOfResponsibility.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Structural/PingPongService/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Verbose", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Structural/Façade/Façade.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Behavioral/Memento/Memento.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Behavioral/Interpreter/Interpreter.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Structural/AdapterVisual/stdafx.cpp: -------------------------------------------------------------------------------- 1 | 2 | // stdafx.cpp : source file that includes just the standard includes 3 | // AdapterVisual.pch will be the pre-compiled header 4 | // stdafx.obj will contain the pre-compiled type information 5 | 6 | #include "stdafx.h" 7 | 8 | 9 | -------------------------------------------------------------------------------- /Structural/Decorator/Decorator.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Structural/NullObject/NullObject.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Behavioral/NullObject/NullObject.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Behavioral/TemplateMethod/TemplateMethod.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Creational/Creational/Monostate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Printer 4 | { 5 | static int id; 6 | public: 7 | int get_id() const { return id; } 8 | void set_id(int value) { id = value; } 9 | }; 10 | 11 | int main_73468() 12 | { 13 | Printer p; 14 | 15 | return 0; 16 | } -------------------------------------------------------------------------------- /Creational/Creational/capitals.txt: -------------------------------------------------------------------------------- 1 | Tokyo 2 | 33200000 3 | New York 4 | 17800000 5 | Sao Paulo 6 | 17700000 7 | Seoul 8 | 17500000 9 | Mexico City 10 | 17400000 11 | Osaka 12 | 16425000 13 | Manila 14 | 14750000 15 | Mumbai 16 | 14350000 17 | Delhi 18 | 14300000 19 | Jakarta 20 | 14250000 -------------------------------------------------------------------------------- /Behavioral/Command/Command.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Structural/Proxy/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Structural/Flyweight/Flyweight.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Behavioral/Mediator/chatroom.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct ChatRoom 4 | { 5 | vector people; // assume append-only 6 | 7 | void join(Person* p); 8 | void broadcast(const string& origin, const string& message); 9 | void message(const string& origin, const string& who, const string& message); 10 | }; 11 | -------------------------------------------------------------------------------- /Behavioral/Strategy/Strategy.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Creational/Creational/CoffeeFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "HotDrink.h" 4 | #include "HotDrinkFactory.h" 5 | 6 | struct HotDrink; 7 | 8 | struct CoffeeFactory : HotDrinkFactory 9 | { 10 | unique_ptr make() const override 11 | { 12 | return make_unique(); 13 | } 14 | }; -------------------------------------------------------------------------------- /Structural/Proxy/Proxy.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Behavioral/ChainOfResponsibility/ChainOfResponsibility.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Behavioral/Observer/new/Observer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | template struct Observer 5 | { 6 | virtual void field_changed( 7 | T& source, // reference to the object that changed 8 | const std::string& field_name // name of field (property) that changed 9 | ) = 0; 10 | }; 11 | 12 | 13 | -------------------------------------------------------------------------------- /Structural/Adapter/Adapter.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Structural/AdapterVisual/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Creational/Creational/PersonBuilder.cpp: -------------------------------------------------------------------------------- 1 | #include "PersonBuilder.h" 2 | #include "PersonAddressBuilder.h" 3 | #include "PersonJobBuilder.h" 4 | 5 | PersonAddressBuilder PersonBuilderBase::lives() const 6 | { 7 | return PersonAddressBuilder{ person }; 8 | } 9 | 10 | PersonJobBuilder PersonBuilderBase::works() const 11 | { 12 | return PersonJobBuilder{ person }; 13 | } 14 | -------------------------------------------------------------------------------- /Behavioral/State/State.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Structural/Bridge/Person.cpp: -------------------------------------------------------------------------------- 1 | #include "Person.h" 2 | 3 | struct Person::PersonImpl 4 | { 5 | void greet(Person* p); 6 | }; 7 | 8 | void Person::PersonImpl::greet(Person* p) 9 | { 10 | printf("hello %s", p->name.c_str()); 11 | } 12 | 13 | Person::Person() 14 | : impl(new PersonImpl) 15 | { 16 | } 17 | 18 | Person::~Person() 19 | { 20 | delete impl; 21 | } 22 | 23 | void Person::greet() 24 | { 25 | impl->greet(this); 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /Structural/Composite/Composite.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Structural/PingPongService/wwwroot/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Behavioral/Observer/Observer.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Structural/Bridge/Person.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct Person 5 | { 6 | std::string name; 7 | 8 | class PersonImpl; 9 | PersonImpl *impl; // bridge - not necessarily inner class, can vary 10 | 11 | Person(); 12 | ~Person(); 13 | 14 | void greet(); 15 | }; 16 | 17 | // pimpl 18 | // binary interfaces are fragile; this removes most of the internals to a separate class 19 | // prevents recompilation of sources reliant on the header -------------------------------------------------------------------------------- /Behavioral/Iterator/Iterator.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Design Patterns in Modern C++*](http://www.apress.com/9781484236024) by Dmitri Nesteruk (Apress, 2018). 4 | 5 | [comment]: #cover 6 | 7 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 8 | 9 | ## Releases 10 | 11 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 12 | 13 | ## Contributions 14 | 15 | See the file Contributing.md for more information on how you can contribute to this repository. -------------------------------------------------------------------------------- /Creational/Creational/Facets.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | #include "Person.h" 9 | #include "PersonBuilder.h" 10 | #include "PersonAddressBuilder.h" 11 | #include "PersonJobBuilder.h" 12 | 13 | int main__() 14 | { 15 | Person p = Person::create() 16 | .lives().at("123 London Road").with_postcode("SW1 1GB").in("London") 17 | .works().at("PragmaSoft").as_a("Consultant").earning(10e6); 18 | 19 | cout << p << endl; 20 | getchar(); 21 | return 0; 22 | } -------------------------------------------------------------------------------- /Creational/Creational.tss: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | C:\Dropbox\Courses\Pluralsight - C++ Design Patterns\Creational\Creational\Serialization.cpp 6 | 7 | 8 | C:\Dropbox\Courses\Pluralsight - C++ Design Patterns\Creational\Creational\Prototype.cpp 9 | 10 | 11 | -------------------------------------------------------------------------------- /Behavioral/Mediator/chat.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #include "person.h" 7 | #include "chatroom.h" 8 | 9 | int main__() 10 | { 11 | ChatRoom room; 12 | 13 | Person john{ "john" }; 14 | Person jane{ "jane" }; 15 | room.join(&john); 16 | room.join(&jane); 17 | john.say("hi room"); 18 | jane.say("oh, hey john"); 19 | 20 | Person simon("simon"); 21 | room.join(&simon); 22 | simon.say("hi everyone!"); 23 | 24 | jane.pm("simon", "glad you could join us, simon"); 25 | 26 | getchar(); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /Behavioral/Mediator/person.cpp: -------------------------------------------------------------------------------- 1 | #include "person.h" 2 | #include "chatroom.h" 3 | 4 | Person::Person(const string& name) : name(name) 5 | { 6 | } 7 | 8 | void Person::receive(const string& origin, const string& message) 9 | { 10 | string s{ origin + ": \"" + message + "\"" }; 11 | cout << "[" << name << "'s chat session] " << s << "\n"; 12 | chat_log.emplace_back(s); 13 | } 14 | 15 | void Person::say(const string& message) const 16 | { 17 | room->broadcast(name, message); 18 | } 19 | 20 | void Person::pm(const string& who, const string& message) const 21 | { 22 | room->message(name, who, message); 23 | } 24 | -------------------------------------------------------------------------------- /Structural/AdapterVisual/Resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by AdapterVisual.rc 4 | // 5 | #define IDR_MAINFRAME 128 6 | #define IDM_ABOUTBOX 0x0010 7 | #define IDD_ABOUTBOX 100 8 | #define IDS_ABOUTBOX 101 9 | #define IDD_ADAPTERVISUAL_DIALOG 102 10 | 11 | // Next default values for new objects 12 | // 13 | #ifdef APSTUDIO_INVOKED 14 | #ifndef APSTUDIO_READONLY_SYMBOLS 15 | 16 | #define _APS_NEXT_RESOURCE_VALUE 129 17 | #define _APS_NEXT_CONTROL_VALUE 1000 18 | #define _APS_NEXT_SYMED_VALUE 101 19 | #define _APS_NEXT_COMMAND_VALUE 32771 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /Behavioral/Visitor/visitor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct Paragraph; 5 | struct BoldParagraph; 6 | struct ListItem; 7 | struct List; 8 | struct Div; 9 | 10 | struct Visitor 11 | { 12 | virtual ~Visitor() = default; 13 | 14 | virtual void visit(const Paragraph& p) = 0; 15 | virtual void visit(const BoldParagraph& p) = 0; 16 | virtual void visit(const ListItem& li) = 0; 17 | // here is the problem 18 | virtual void visit(const List& l) = 0; 19 | virtual void visit(const Div& div) = 0; 20 | 21 | // need to add another visit function whenever a new type is added 22 | 23 | virtual std::string str() const = 0; 24 | }; 25 | -------------------------------------------------------------------------------- /Creational/Creational/HotDrink.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct HotDrink 8 | { 9 | virtual ~HotDrink() = default; 10 | 11 | virtual void prepare(int volume) = 0; 12 | }; 13 | 14 | struct Tea : HotDrink 15 | { 16 | 17 | void prepare(int volume) override 18 | { 19 | cout << "Take tea bag, boil water, pour " << volume << "ml, add some lemon" << endl; 20 | } 21 | }; 22 | 23 | struct Coffee : HotDrink 24 | { 25 | void prepare(int volume) override 26 | { 27 | cout << "Grind some beans, boil water, pour " << volume << "ml, add cream, enjoy!" << endl; 28 | } 29 | }; -------------------------------------------------------------------------------- /Creational/Creational/AbstractFactory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "HotDrink.h" 5 | #include "DrinkFactory.h" 6 | using namespace std; 7 | 8 | unique_ptr make_drink(string type) 9 | { 10 | unique_ptr drink; 11 | if (type == "tea") 12 | { 13 | drink = make_unique(); 14 | drink->prepare(200); 15 | } 16 | else 17 | { 18 | drink = make_unique(); 19 | drink->prepare(50); 20 | } 21 | return drink; 22 | } 23 | 24 | int main53() 25 | { 26 | auto d = make_drink("tea"); 27 | 28 | DrinkFactory df; 29 | df.make_drink("coffee"); 30 | 31 | getchar(); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /Creational/Creational/PersonAddressBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class PersonAddressBuilder : public PersonBuilderBase 5 | { 6 | typedef PersonAddressBuilder Self; 7 | public: 8 | explicit PersonAddressBuilder(Person& person) 9 | : PersonBuilderBase{person} 10 | { 11 | } 12 | 13 | Self& at(std::string street_address) 14 | { 15 | person.street_address = street_address; 16 | return *this; 17 | } 18 | 19 | Self& with_postcode(std::string post_code) 20 | { 21 | person.post_code = post_code; 22 | return *this; 23 | } 24 | 25 | Self& in(std::string city) 26 | { 27 | person.city = city; 28 | return *this; 29 | } 30 | }; -------------------------------------------------------------------------------- /Creational/Creational/PersonJobBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PersonBuilder.h" 3 | 4 | class PersonJobBuilder : public PersonBuilderBase 5 | { 6 | typedef PersonJobBuilder Self; 7 | public: 8 | explicit PersonJobBuilder(Person& person) 9 | : PersonBuilderBase { person } 10 | { 11 | } 12 | 13 | Self& at(std::string company_name) 14 | { 15 | person.company_name = company_name; 16 | return *this; 17 | } 18 | 19 | Self& as_a(std::string position) 20 | { 21 | person.position = position; 22 | return *this; 23 | } 24 | 25 | Self& earning(int annual_income) 26 | { 27 | person.annual_income = annual_income; 28 | return *this; 29 | } 30 | }; -------------------------------------------------------------------------------- /Structural/AdapterVisual/AdapterVisual.h: -------------------------------------------------------------------------------- 1 | 2 | // AdapterVisual.h : main header file for the PROJECT_NAME application 3 | // 4 | 5 | #pragma once 6 | 7 | #ifndef __AFXWIN_H__ 8 | #error "include 'stdafx.h' before including this file for PCH" 9 | #endif 10 | 11 | #include "resource.h" // main symbols 12 | 13 | 14 | // CAdapterVisualApp: 15 | // See AdapterVisual.cpp for the implementation of this class 16 | // 17 | 18 | class CAdapterVisualApp : public CWinApp 19 | { 20 | public: 21 | CAdapterVisualApp(); 22 | 23 | // Overrides 24 | public: 25 | virtual BOOL InitInstance(); 26 | 27 | // Implementation 28 | 29 | DECLARE_MESSAGE_MAP() 30 | }; 31 | 32 | extern CAdapterVisualApp theApp; -------------------------------------------------------------------------------- /Creational/Creational/PersonBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Person.h" 3 | 4 | class PersonAddressBuilder; 5 | class PersonJobBuilder; 6 | 7 | class PersonBuilderBase 8 | { 9 | protected: 10 | Person& person; 11 | explicit PersonBuilderBase(Person& person) 12 | : person{ person } 13 | { 14 | } 15 | public: 16 | operator Person() const 17 | { 18 | return std::move(person); 19 | } 20 | 21 | // builder facets 22 | 23 | PersonAddressBuilder lives() const; 24 | PersonJobBuilder works() const; 25 | }; 26 | 27 | class PersonBuilder : public PersonBuilderBase 28 | { 29 | Person p; 30 | public: 31 | PersonBuilder(): PersonBuilderBase{p} 32 | { 33 | } 34 | 35 | }; -------------------------------------------------------------------------------- /Structural/Bridge/Bridge.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pimpl 7 | 8 | 9 | 10 | 11 | 12 | {bb52ed5a-ff28-4602-a5ca-04cdaa5eae14} 13 | 14 | 15 | 16 | 17 | Pimpl 18 | 19 | 20 | -------------------------------------------------------------------------------- /Structural/PingPongService/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:9149/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "api/values", 15 | "environmentVariables": { 16 | "Hosting:Environment": "Development" 17 | } 18 | }, 19 | "web": { 20 | "commandName": "web", 21 | "environmentVariables": { 22 | "Hosting:Environment": "Development" 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /Behavioral/Visitor/Visitor.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Behavioral/Mediator/person.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct ChatRoom; 8 | 9 | struct Person 10 | { 11 | string name; 12 | ChatRoom* room = nullptr; 13 | 14 | Person(const string& name); 15 | void receive(const string& origin, const string& message); 16 | 17 | void say(const string& message) const; 18 | vector chat_log; 19 | 20 | void pm(const string& who, const string& message) const; 21 | 22 | // generated in IDE 23 | friend bool operator==(const Person& lhs, const Person& rhs) 24 | { 25 | return lhs.name == rhs.name; 26 | } 27 | 28 | friend bool operator!=(const Person& lhs, const Person& rhs) 29 | { 30 | return !(lhs == rhs); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /Behavioral/Mediator/chatroom.cpp: -------------------------------------------------------------------------------- 1 | #include "person.h" 2 | #include "chatroom.h" 3 | #include 4 | 5 | void ChatRoom::broadcast(const string& origin, const string& message) 6 | { 7 | for (auto p : people) 8 | if (p->name != origin) 9 | p->receive(origin, message); 10 | } 11 | 12 | void ChatRoom::join(Person* p) 13 | { 14 | string join_msg = p->name + " joins the chat"; 15 | broadcast("room", join_msg); 16 | 17 | p->room = this; 18 | people.push_back(p); 19 | } 20 | 21 | void ChatRoom::message(const string& origin, const string& who, const string& message) 22 | { 23 | auto target = find_if(begin(people), end(people), [&](const Person* p) { return p->name == who; }); 24 | if (target != end(people)) 25 | { 26 | (*target)->receive(origin, message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Behavioral/Observer/new/Observable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template struct Observer; 7 | 8 | template struct Observable 9 | { 10 | // should this be an std::set? 11 | std::vector*> observers; 12 | public: 13 | // informs all observers when a change is made 14 | void notify(T& source, const std::string& field_name) 15 | { 16 | for (auto observer : observers) 17 | observer->field_changed(source, field_name); 18 | } 19 | 20 | void subscribe(Observer& observer) 21 | { 22 | observers.push_back(&observer); 23 | } 24 | 25 | void unsubscribe(Observer& observer) 26 | { 27 | observers.erase( 28 | remove(observers.begin(), observers.end(), &observer), 29 | observers.end() 30 | ); 31 | } 32 | }; -------------------------------------------------------------------------------- /Creational/Creational/Factory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum class PointType 4 | { 5 | cartesian, 6 | polar 7 | }; 8 | 9 | class Point 10 | { 11 | /*Point(float a, float b, PointType type = PointType::cartesian) 12 | { 13 | if (type == PointType::cartesian) 14 | { 15 | x = a; b = y; 16 | } 17 | else 18 | { 19 | x = a*cos(b); 20 | y = a*sin(b); 21 | } 22 | }*/ 23 | 24 | // use a factory method 25 | Point(float x, float y) : x(x), y(y){} 26 | public: 27 | float x, y; 28 | 29 | friend class PointFactory; 30 | }; 31 | 32 | class PointFactory 33 | { 34 | static Point NewCartesian(float x, float y) 35 | { 36 | return Point{ x,y }; 37 | } 38 | 39 | static Point NewPolar(float r, float theta) 40 | { 41 | return Point{ r*cos(theta), r*sin(theta) }; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /Creational/Creational/BoostDIDemo.hpp: -------------------------------------------------------------------------------- 1 | #include "di.hpp" 2 | #include "headers.hpp" 3 | 4 | 5 | struct IFoo 6 | { 7 | virtual string name() = 0; 8 | }; 9 | 10 | struct Foo : IFoo 11 | { 12 | static int id; 13 | Foo() { ++id; } 14 | string name() override 15 | { 16 | return "foo "s + lexical_cast(id); 17 | } 18 | }; 19 | 20 | int Foo::id = 0; 21 | 22 | struct Bar 23 | { 24 | std::shared_ptr foo; 25 | }; 26 | 27 | int main() 28 | { 29 | auto injector = di::make_injector( 30 | di::bind().to().in(di::singleton) 31 | ); 32 | auto bar1 = injector.create>(); 33 | auto bar2 = injector.create>(); 34 | 35 | cout << bar1->foo->name() << endl; 36 | cout << bar2->foo->name() << endl; 37 | 38 | cout << boolalpha 39 | << (bar1->foo.get() == bar2->foo.get()) 40 | << endl; 41 | } -------------------------------------------------------------------------------- /Behavioral/NullObject/null_object.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct Log 6 | { 7 | virtual void LogInfo(const string& message) const = 0; 8 | }; 9 | 10 | struct ConsoleLog : Log 11 | { 12 | void LogInfo(const string& message) const override 13 | { 14 | cout << message << endl; 15 | } 16 | }; 17 | 18 | template 19 | struct PaymentProcessing 20 | { 21 | static_assert(is_base_of::value, "LogType must be a Log"); 22 | 23 | LogType log; 24 | 25 | // alternatively, ctor 26 | 27 | void Process() 28 | { 29 | log.LogMessage("Processing payments..."); 30 | } 31 | }; 32 | 33 | int main() 34 | { 35 | struct NullLog : Log 36 | { 37 | void LogInfo(const string& message) const override 38 | { 39 | } 40 | }; 41 | 42 | PaymentProcessing pp; 43 | 44 | getchar(); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /Behavioral/Observer/new/headers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _USE_MATH_DEFINES 4 | #define _HAS_AUTO_PTR_ETC 1 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | //using namespace std::string_literals; 23 | 24 | //#include 25 | //#include 26 | //#include 27 | //#include 28 | #include 29 | //#include 30 | using namespace boost; 31 | using namespace boost::signals2; 32 | 33 | #define GTEST_LANG_CXX11 1 34 | #include -------------------------------------------------------------------------------- /Behavioral/Visitor/std_visit.cpp: -------------------------------------------------------------------------------- 1 | #include "Headers.hpp" 2 | 3 | struct AddressPrinter 4 | { 5 | void operator()(const string& house_name) const { 6 | cout << "A house called " << house_name << "\n"; 7 | } 8 | 9 | void operator()(const int house_number) const { 10 | cout << "House number " << house_number << "\n"; 11 | } 12 | }; 13 | 14 | int main(int ac, char* av[]) 15 | { 16 | variant house; 17 | //house = "Montefiore Castle"; 18 | house = 221; 19 | 20 | AddressPrinter ap; 21 | std::visit(ap, house); 22 | 23 | // what if you want to create a visitor in-place? 24 | std::visit([](auto& arg) { 25 | using T = decay_t; 26 | 27 | if constexpr (is_same_v) 28 | { 29 | cout << "A house called " << arg.c_str() << "\n"; 30 | } 31 | else 32 | { 33 | cout << "House number " << arg << "\n"; 34 | } 35 | }, house); 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /Creational/Creational/SingletonTests.cpp: -------------------------------------------------------------------------------- 1 | #include "Singleton.hpp" 2 | #include 3 | 4 | //TEST(DatabaseTests, IsSingletonTest) 5 | //{ 6 | // auto& db = SingletonDatabase::get(); 7 | // auto& db2 = SingletonDatabase::get(); 8 | // ASSERT_EQ(1, db.instance_count); 9 | // ASSERT_EQ(1, db2.instance_count); 10 | //} 11 | 12 | TEST(RecordFinderTests, SingletonTotalPopulationTest) 13 | { 14 | SingletonRecordFinder rf; 15 | std::vector names{ "Seoul", "Mexico City" }; 16 | int tp = rf.total_population(names); 17 | EXPECT_EQ(17500000 + 17400000, tp); 18 | } 19 | 20 | TEST(RecordFinderTests, DependantTotalPopulationTest) 21 | { 22 | DummyDatabase db{}; 23 | ConfigurableRecordFinder rf{ db }; 24 | EXPECT_EQ(4, rf.total_population( 25 | std::vector{"alpha", "gamma"})); 26 | } 27 | 28 | int dsfmain(int ac, char* av[]) 29 | { 30 | testing::InitGoogleTest(&ac, av); 31 | return RUN_ALL_TESTS(); 32 | } -------------------------------------------------------------------------------- /Structural/Composite/graphics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | struct GraphicObject 7 | { 8 | virtual void draw() = 0; 9 | }; 10 | 11 | struct Circle : GraphicObject 12 | { 13 | void draw() override 14 | { 15 | std::cout << "Circle" << std::endl; 16 | } 17 | }; 18 | 19 | struct Group : GraphicObject 20 | { 21 | std::string name; 22 | 23 | 24 | explicit Group(const std::string& name) 25 | : name{name} 26 | { 27 | } 28 | 29 | void draw() override 30 | { 31 | std::cout << "Group " << name.c_str() << " contains:" << std::endl; 32 | for (auto&& o : objects) 33 | o->draw(); 34 | } 35 | 36 | std::vector objects; 37 | }; 38 | 39 | inline void graphics() 40 | { 41 | Group root("root"); 42 | Circle c1, c2; 43 | root.objects.push_back(&c1); 44 | 45 | Group subgroup("sub"); 46 | subgroup.objects.push_back(&c2); 47 | 48 | root.objects.push_back(&subgroup); 49 | 50 | root.draw(); 51 | } -------------------------------------------------------------------------------- /Behavioral/Observer/observer3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | #include 5 | using namespace boost; 6 | using namespace signals2; 7 | 8 | namespace { 9 | 10 | template 11 | struct Observable 12 | { 13 | virtual ~Observable() = default; 14 | signal property_changed; 15 | }; 16 | 17 | struct Person : Observable 18 | { 19 | explicit Person(int age) 20 | : age(age) 21 | { 22 | } 23 | 24 | int get_age() const 25 | { 26 | return age; 27 | } 28 | 29 | void set_age(const int age) 30 | { 31 | if (this->age == age) return; 32 | 33 | this->age = age; 34 | property_changed(*this, "age"); 35 | } 36 | 37 | private: 38 | int age; 39 | }; 40 | 41 | int main_() 42 | { 43 | Person p{123}; 44 | p.property_changed.connect([](Person&, const string& prop_name) 45 | { 46 | cout << prop_name << " has been changed" << endl; 47 | }); 48 | p.set_age(20); 49 | 50 | getchar(); 51 | return 0; 52 | } 53 | } -------------------------------------------------------------------------------- /Structural/AdapterVisual/AdapterVisualDlg.h: -------------------------------------------------------------------------------- 1 | 2 | // AdapterVisualDlg.h : header file 3 | // 4 | 5 | #pragma once 6 | #include 7 | #include "Geometry.h" 8 | 9 | // CAdapterVisualDlg dialog 10 | class CAdapterVisualDlg : public CDialogEx 11 | { 12 | // Construction 13 | public: 14 | CAdapterVisualDlg(CWnd* pParent = NULL); // standard constructor 15 | 16 | // Dialog Data 17 | #ifdef AFX_DESIGN_TIME 18 | enum { IDD = IDD_ADAPTERVISUAL_DIALOG }; 19 | #endif 20 | 21 | protected: 22 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 23 | 24 | 25 | // Implementation 26 | protected: 27 | HICON m_hIcon; 28 | 29 | void DrawPoints(CPaintDC& dc, std::vector::iterator start, std::vector::iterator end) 30 | { 31 | for (auto i = start; i != end; ++i) 32 | dc.SetPixel(i->x, i->y, 0); 33 | } 34 | 35 | // Generated message map functions 36 | virtual BOOL OnInitDialog(); 37 | afx_msg void OnSysCommand(UINT nID, LPARAM lParam); 38 | afx_msg void OnPaint(); 39 | afx_msg HCURSOR OnQueryDragIcon(); 40 | DECLARE_MESSAGE_MAP() 41 | }; 42 | -------------------------------------------------------------------------------- /Creational/Creational/FactoryCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | namespace FactoryExercise { 7 | 8 | struct Person 9 | { 10 | int id; 11 | string name; 12 | }; 13 | 14 | class PersonFactory 15 | { 16 | int id{ 0 }; 17 | public: 18 | Person create_person(const string& name) 19 | { 20 | return { id++, name }; 21 | } 22 | }; 23 | 24 | #include "gtest/gtest.h" 25 | 26 | //#include "helpers/iohelper.h" 27 | 28 | //#include "exercise.cpp" 29 | 30 | 31 | namespace 32 | { 33 | class Evaluate : public testing::Test 34 | { 35 | }; 36 | 37 | TEST_F(Evaluate, SimplePersonTest) 38 | { 39 | PersonFactory pf; 40 | 41 | auto p1 = pf.create_person("Chris"); 42 | ASSERT_EQ("Chris", p1.name); 43 | 44 | auto p2 = pf.create_person("Sarah"); 45 | ASSERT_EQ(1, p2.id) << "Expected the second created person's id to be = 1"; 46 | } 47 | } // namespace 48 | 49 | } 50 | 51 | int main(int ac, char* av[]) 52 | { 53 | testing::InitGoogleTest(&ac, av); 54 | return RUN_ALL_TESTS(); 55 | } -------------------------------------------------------------------------------- /Creational/Creational/SingletonCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct SingletonTester 5 | { 6 | template 7 | bool is_singleton(function factory) 8 | { 9 | T* _1 = factory(); 10 | T* _2 = factory(); 11 | return _1 == _2; 12 | } 13 | }; 14 | 15 | #include "gtest/gtest.h" 16 | 17 | //#include "helpers/iohelper.h" 18 | 19 | //#include "exercise.cpp" 20 | 21 | 22 | namespace 23 | { 24 | class Evaluate : public testing::Test 25 | { 26 | }; 27 | 28 | TEST_F(Evaluate, SimpleTest) 29 | { 30 | SingletonTester tester; 31 | ASSERT_TRUE(tester.is_singleton( 32 | [&]() -> SingletonTester* { return &tester; })) 33 | << "Expected a singleton in this case; provided lambda is yielding the same object over and over."; 34 | ASSERT_FALSE(tester.is_singleton([]() { return new SingletonTester{}; })); 35 | } 36 | } // namespace 37 | 38 | 39 | //int main(int ac, char* av[]) 40 | //{ 41 | // testing::InitGoogleTest(&ac, av); 42 | // return RUN_ALL_TESTS(); 43 | //} 44 | -------------------------------------------------------------------------------- /Structural/PingPongService/Controllers/PingPongController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNet.Mvc; 6 | 7 | namespace PingPongService.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | public class PingPongController : Controller 11 | { 12 | // GET: api/values 13 | [HttpGet] 14 | public IEnumerable Get() 15 | { 16 | return new string[] { "value1", "value2" }; 17 | } 18 | 19 | // GET api/values/5 20 | [HttpGet("{msg}")] 21 | public string Get(string msg) 22 | { 23 | return msg + " pong"; 24 | } 25 | 26 | // POST api/values 27 | [HttpPost] 28 | public void Post([FromBody]string value) 29 | { 30 | } 31 | 32 | // PUT api/values/5 33 | [HttpPut("{id}")] 34 | public void Put(int id, [FromBody]string value) 35 | { 36 | } 37 | 38 | // DELETE api/values/5 39 | [HttpDelete("{id}")] 40 | public void Delete(int id) 41 | { 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Creational/Creational/FactoryMethod.cpp: -------------------------------------------------------------------------------- 1 | #define _USE_MATH_DEFINES 2 | #include 3 | #include 4 | 5 | enum class PointType 6 | { 7 | cartesian, 8 | polar 9 | }; 10 | 11 | class Point 12 | { 13 | /*Point(float a, float b, PointType type = PointType::cartesian) 14 | { 15 | if (type == PointType::cartesian) 16 | { 17 | x = a; b = y; 18 | } 19 | else 20 | { 21 | x = a*cos(b); 22 | y = a*sin(b); 23 | } 24 | }*/ 25 | 26 | 27 | Point(const float x, const float y) 28 | : x{x}, 29 | y{y} 30 | { 31 | } 32 | 33 | public: 34 | float x, y; 35 | 36 | 37 | friend std::ostream& operator<<(std::ostream& os, const Point& obj) 38 | { 39 | return os 40 | << "x: " << obj.x 41 | << " y: " << obj.y; 42 | } 43 | 44 | static Point NewCartesian(float x, float y) 45 | { 46 | return{ x,y }; 47 | } 48 | static Point NewPolar(float r, float theta) 49 | { 50 | return{ r*cos(theta), r*sin(theta) }; 51 | } 52 | }; 53 | 54 | int main_z() 55 | { 56 | // will not work 57 | //Point p{ 1,2 }; 58 | 59 | auto p = Point::NewPolar(5, M_PI_4); 60 | std::cout << p << std::endl; 61 | 62 | getchar(); 63 | return 0; 64 | } -------------------------------------------------------------------------------- /Creational/Creational/DrinkFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "HotDrink.h" 4 | #include "TeaFactory.h" 5 | #include "CoffeeFactory.h" 6 | #include 7 | #include 8 | 9 | struct HotDrink; 10 | 11 | class DrinkFactory 12 | { 13 | map> hot_factories; 14 | public: 15 | DrinkFactory() 16 | { 17 | hot_factories["coffee"] = make_unique(); 18 | hot_factories["tea"] = make_unique(); 19 | } 20 | 21 | unique_ptr make_drink(const string& name) 22 | { 23 | auto drink = hot_factories[name]->make(); 24 | drink->prepare(200); // oops! 25 | return drink; 26 | } 27 | }; 28 | 29 | class DrinkWithVolumeFactory 30 | { 31 | map()>> factories; 32 | public: 33 | 34 | DrinkWithVolumeFactory() 35 | { 36 | factories["tea"] = [] { 37 | auto tea = make_unique(); 38 | tea->prepare(200); 39 | return tea; 40 | }; 41 | } 42 | 43 | unique_ptr make_drink(const string& name); 44 | }; 45 | 46 | inline unique_ptr DrinkWithVolumeFactory::make_drink(const string& name) 47 | { 48 | return factories[name](); 49 | } 50 | -------------------------------------------------------------------------------- /Behavioral/Mediator/Mediator.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | chatroom 6 | 7 | 8 | chatroom 9 | 10 | 11 | chatroom 12 | 13 | 14 | soccer 15 | 16 | 17 | 18 | 19 | {8afe6fe8-628f-4c42-9336-1888d26d7370} 20 | 21 | 22 | {50ca6257-88ca-442c-9c65-99f125b87a06} 23 | 24 | 25 | 26 | 27 | chatroom 28 | 29 | 30 | chatroom 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Creational/Creational/InnerFactory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // do not need this for factory 4 | enum class PointType 5 | { 6 | cartesian, 7 | polar 8 | }; 9 | 10 | class Point 11 | { 12 | /*Point(float a, float b, PointType type = PointType::cartesian) 13 | { 14 | if (type == PointType::cartesian) 15 | { 16 | x = a; b = y; 17 | } 18 | else 19 | { 20 | x = a*cos(b); 21 | y = a*sin(b); 22 | } 23 | }*/ 24 | 25 | // use a factory method 26 | Point(float x, float y) : x(x), y(y) {} 27 | 28 | class PointFactory 29 | { 30 | PointFactory() {} 31 | public: 32 | static Point NewCartesian(float x, float y) 33 | { 34 | return { x,y }; 35 | } 36 | static Point NewPolar(float r, float theta) 37 | { 38 | return{ r*cos(theta), r*sin(theta) }; 39 | } 40 | }; 41 | public: 42 | float x, y; 43 | static PointFactory Factory; 44 | }; 45 | 46 | int main_2() 47 | { 48 | // will not work 49 | // Point p{ 1,2 }; 50 | 51 | // nope! 52 | // Point::PointFactory pf; 53 | 54 | // if factory is public, then 55 | //auto p = Point::PointFactory::NewCartesian(3, 4); 56 | 57 | // at any rate, use this 58 | auto pp = Point::Factory.NewCartesian(2, 3); 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /Creational/Creational/SRP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct Journal 9 | { 10 | string title; 11 | vector entries; 12 | 13 | explicit Journal(const string& title) 14 | : title{title} 15 | { 16 | } 17 | 18 | void add(const string& entry); 19 | 20 | // persistence is a separate concern 21 | void save(const string& filename); 22 | }; 23 | 24 | void Journal::add(const string& entry) 25 | { 26 | static int count = 1; 27 | entries.push_back(boost::lexical_cast(count++) 28 | + ": " + entry); 29 | } 30 | 31 | void Journal::save(const string& filename) 32 | { 33 | ofstream ofs(filename); 34 | for (auto& s : entries) 35 | ofs << s << endl; 36 | } 37 | 38 | struct PersistenceManager 39 | { 40 | static void save(const Journal& j, const string& filename) 41 | { 42 | ofstream ofs(filename); 43 | for (auto& s : j.entries) 44 | ofs << s << endl; 45 | } 46 | }; 47 | 48 | void main() 49 | { 50 | Journal journal{"Dear Diary"}; 51 | journal.add("I ate a bug"); 52 | journal.add("I cried today"); 53 | 54 | //journal.save("diary.txt"); 55 | 56 | PersistenceManager pm; 57 | pm.save(journal, "diary.txt"); 58 | } -------------------------------------------------------------------------------- /Behavioral/Visitor/visitor_intrusive.cpp: -------------------------------------------------------------------------------- 1 | // visitor examples for design patterns c++ book 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct Expression 8 | { 9 | virtual void print(ostringstream& oss) = 0; 10 | }; 11 | 12 | struct DoubleExpression : Expression 13 | { 14 | double value; 15 | explicit DoubleExpression(const double value) 16 | : value{value} {} 17 | 18 | void print(ostringstream& oss) override 19 | { 20 | oss << value; 21 | } 22 | }; 23 | 24 | struct AdditionExpression : Expression 25 | { 26 | Expression *left, *right; 27 | 28 | AdditionExpression(Expression* const left, Expression* const right) 29 | : left{left}, right{right} {} 30 | 31 | ~AdditionExpression() 32 | { 33 | delete left; 34 | delete right; 35 | } 36 | 37 | void print(ostringstream& oss) override 38 | { 39 | oss << "("; 40 | left->print(oss); 41 | oss << "+"; 42 | right->print(oss); 43 | oss << ")"; 44 | } 45 | }; 46 | 47 | void main_2_() 48 | { 49 | auto e = new AdditionExpression{ 50 | new DoubleExpression{1}, 51 | new AdditionExpression{ 52 | new DoubleExpression{2}, 53 | new DoubleExpression{3} 54 | } 55 | }; 56 | ostringstream oss; 57 | e->print(oss); 58 | cout << oss.str() << endl; 59 | } -------------------------------------------------------------------------------- /Behavioral/Observer/new/SaferObservable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | template struct Observer; 9 | 10 | template struct SaferObservable 11 | { 12 | std::vector*> observers; 13 | //std::mutex mtx; 14 | typedef std::recursive_mutex mutex_t; 15 | mutex_t mtx; // not recommended 16 | public: 17 | // informs all observers when a change is made 18 | void notify(T& source, const std::string& field_name) 19 | { 20 | std::scoped_lock lock{mtx}; 21 | for (auto observer : observers) 22 | if (observer) // added for reentrancy 23 | observer->field_changed(source, field_name); 24 | } 25 | 26 | void subscribe(Observer& observer) 27 | { 28 | std::scoped_lock lock{mtx}; 29 | observers.push_back(&observer); 30 | } 31 | 32 | void unsubscribe(Observer& observer) 33 | { 34 | // std::scoped_lock lock{mtx}; 35 | // observers.erase( 36 | // remove(observers.begin(), observers.end(), &observer), 37 | // observers.end() 38 | // ); 39 | 40 | // avoid taking a lock here 41 | // avoid removal of the object 42 | auto it = std::find(begin(observers), end(observers), &observer); 43 | if (it != end(observers)) 44 | *it = nullptr; // not viable for an std::set 45 | } 46 | }; -------------------------------------------------------------------------------- /Creational/Creational/PrototypeCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | struct Point 2 | { 3 | int x{ 0 }, y{ 0 }; 4 | 5 | Point(){} 6 | 7 | Point(const int x, const int y) : x{x}, y{y} {} 8 | }; 9 | 10 | struct Line 11 | { 12 | Point *start, *end; 13 | 14 | Line(Point* const start, Point* const end) 15 | : start(start), end(end) 16 | { 17 | } 18 | 19 | ~Line() 20 | { 21 | delete start; 22 | delete end; 23 | } 24 | 25 | Line deep_copy() const 26 | { 27 | return Line{ 28 | new Point(start->x, start->y), 29 | new Point(end->x, end->y) 30 | }; 31 | } 32 | }; 33 | 34 | #include "gtest/gtest.h" 35 | 36 | //#include "helpers/iohelper.h" 37 | 38 | //#include "exercise.cpp" 39 | 40 | 41 | namespace 42 | { 43 | class Evaluate : public testing::Test 44 | { 45 | }; 46 | 47 | TEST_F(Evaluate, SimpleTest) 48 | { 49 | Line line1{ 50 | new Point{3,3}, 51 | new Point{10,10} 52 | }; 53 | 54 | auto line2 = line1.deep_copy(); 55 | line1.start->x = line1.start->y = 56 | line1.end->y = line1.end->y = 0; 57 | 58 | ASSERT_EQ(3, line2.start->x); 59 | ASSERT_EQ(3, line2.start->y); 60 | ASSERT_EQ(10, line2.end->x); 61 | ASSERT_EQ(10, line2.end->y); 62 | } 63 | } // namespace 64 | 65 | int main(int ac, char* av[]) 66 | { 67 | testing::InitGoogleTest(&ac, av); 68 | return RUN_ALL_TESTS(); 69 | } -------------------------------------------------------------------------------- /Creational/Creational/ISP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | struct Document; 3 | 4 | //struct IMachine 5 | //{ 6 | // virtual void print(Document& doc) = 0; 7 | // virtual void fax(Document& doc) = 0; 8 | // virtual void scan(Document& doc) = 0; 9 | //}; 10 | // 11 | //struct MFP : IMachine 12 | //{ 13 | // void print(Document& doc) override; 14 | // void fax(Document& doc) override; 15 | // void scan(Document& doc) override; 16 | //}; 17 | 18 | // 1. Recompile 19 | // 2. Client does not need this 20 | // 3. Forcing implementors to implement too much 21 | 22 | struct IPrinter 23 | { 24 | virtual void print(Document& doc) = 0; 25 | }; 26 | 27 | struct IScanner 28 | { 29 | virtual void scan(Document& doc) = 0; 30 | }; 31 | 32 | struct Printer : IPrinter 33 | { 34 | void print(Document& doc) override; 35 | }; 36 | 37 | struct Scanner : IScanner 38 | { 39 | void scan(Document& doc) override; 40 | }; 41 | 42 | struct IMachine: IPrinter, IScanner 43 | { 44 | }; 45 | 46 | struct Machine : IMachine 47 | { 48 | IPrinter& printer; 49 | IScanner& scanner; 50 | 51 | Machine(IPrinter& printer, IScanner& scanner) 52 | : printer{printer}, 53 | scanner{scanner} 54 | { 55 | } 56 | 57 | void print(Document& doc) override { 58 | printer.print(doc); 59 | } 60 | void scan(Document& doc) override; 61 | }; 62 | 63 | // IPrinter --> Printer 64 | // everything --> Machine -------------------------------------------------------------------------------- /Behavioral/Iterator/facade.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #include 7 | 8 | 9 | struct Node 10 | { 11 | string value; 12 | Node* next = nullptr; 13 | 14 | explicit Node(const string& value) 15 | : value(value) 16 | { 17 | } 18 | 19 | 20 | Node(const string& value, Node* const parent) 21 | : value(value) 22 | { 23 | parent->next = this; 24 | } 25 | }; 26 | 27 | struct ListIterator : boost::iterator_facade 29 | { 30 | Node* current = nullptr; 31 | 32 | 33 | ListIterator() 34 | { 35 | } 36 | 37 | explicit ListIterator(Node* const current) 38 | : current(current) 39 | { 40 | } 41 | 42 | private: 43 | friend class boost::iterator_core_access; 44 | 45 | void increment() { current = current->next; } 46 | 47 | bool equal(const ListIterator& other) const 48 | { return other.current == current; }; 49 | 50 | Node& dereference() const 51 | { return *current; } 52 | }; 53 | 54 | int main_0() 55 | { 56 | Node alpha{ "alpha" }; 57 | Node beta{ "beta", &alpha}; 58 | Node gamma{ "gamma", &beta }; 59 | 60 | for_each(ListIterator{ &alpha }, ListIterator{}, 61 | [](const Node& n) 62 | { 63 | cout << n.value << endl; 64 | }); 65 | 66 | getchar(); 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /Creational/Creational.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Creational", "Creational\Creational.vcxproj", "{A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}.Debug|x64.ActiveCfg = Debug|x64 17 | {A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}.Debug|x64.Build.0 = Debug|x64 18 | {A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}.Debug|x86.ActiveCfg = Debug|Win32 19 | {A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}.Debug|x86.Build.0 = Debug|Win32 20 | {A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}.Release|x64.ActiveCfg = Release|x64 21 | {A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}.Release|x64.Build.0 = Release|x64 22 | {A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}.Release|x86.ActiveCfg = Release|Win32 23 | {A2EAA3EF-D92C-41AA-A184-08A58D77FF1F}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /Behavioral/State/classic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | class LightSwitch; 6 | 7 | struct State 8 | { 9 | virtual void on(LightSwitch *ls) 10 | { 11 | cout << "Light is already on\n"; 12 | } 13 | virtual void off(LightSwitch *ls) 14 | { 15 | cout << "Light is already off\n"; 16 | } 17 | }; 18 | 19 | struct OnState : State 20 | { 21 | OnState() 22 | { 23 | cout << "Light turned on\n"; 24 | } 25 | 26 | void off(LightSwitch* ls) override; 27 | }; 28 | 29 | struct OffState : State 30 | { 31 | OffState() 32 | { 33 | cout << "Light turned off\n"; 34 | } 35 | 36 | void on(LightSwitch* ls) override; 37 | }; 38 | 39 | class LightSwitch 40 | { 41 | State *state; 42 | public: 43 | LightSwitch() 44 | { 45 | state = new OffState(); 46 | } 47 | void set_state(State* state) 48 | { 49 | this->state = state; 50 | } 51 | void on() { state->on(this); } 52 | void off() { state->off(this); } 53 | }; 54 | 55 | void OnState::off(LightSwitch* ls) 56 | { 57 | cout << "Switching light off...\n"; 58 | ls->set_state(new OffState()); 59 | delete this; 60 | } 61 | 62 | void OffState::on(LightSwitch* ls) 63 | { 64 | cout << "Switching light on...\n"; 65 | ls->set_state(new OnState()); 66 | delete this; 67 | } 68 | 69 | void main_3() 70 | { 71 | LightSwitch ls; 72 | ls.on(); 73 | ls.off(); 74 | ls.off(); 75 | getchar(); 76 | } -------------------------------------------------------------------------------- /Behavioral/TemplateMethod/template_method.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | class Game 6 | { 7 | public: 8 | explicit Game(int number_of_players) 9 | : number_of_players(number_of_players) 10 | { 11 | } 12 | 13 | void run() 14 | { 15 | start(); 16 | while (!have_winner()) 17 | take_turn(); 18 | cout << "Player " << get_winner() << " wins.\n"; 19 | } 20 | 21 | protected: 22 | virtual void start() = 0; 23 | virtual bool have_winner() = 0; 24 | virtual void take_turn() = 0; 25 | virtual int get_winner() = 0; 26 | 27 | int current_player{ 0 }; 28 | int number_of_players; 29 | }; 30 | 31 | class Chess : public Game 32 | { 33 | public: 34 | explicit Chess() : Game{ 2 } {} 35 | 36 | protected: 37 | void start() override 38 | { 39 | cout << "Starting a game of chess with " << number_of_players << " players\n"; 40 | } 41 | 42 | bool have_winner() override 43 | { 44 | return turns == max_turns; 45 | } 46 | 47 | void take_turn() override 48 | { 49 | cout << "Turn " << turns << " taken by player " << current_player << "\n"; 50 | turns++; 51 | current_player = (current_player + 1) % number_of_players; 52 | } 53 | 54 | int get_winner() override 55 | { 56 | return current_player; 57 | } 58 | 59 | private: 60 | int turns{ 0 }, max_turns{ 10 }; 61 | }; 62 | 63 | int main() 64 | { 65 | Chess chess; 66 | chess.run(); 67 | 68 | getchar(); 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Freeware License, some rights reserved 2 | 3 | Copyright (c) 2018 Dmitri Nesteruk 4 | 5 | Permission is hereby granted, free of charge, to anyone obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to work with the Software within the limits of freeware distribution and fair use. 8 | This includes the rights to use, copy, and modify the Software for personal use. 9 | Users are also allowed and encouraged to submit corrections and modifications 10 | to the Software for the benefit of other users. 11 | 12 | It is not allowed to reuse, modify, or redistribute the Software for 13 | commercial use in any way, or for a user’s educational materials such as books 14 | or blog articles without prior permission from the copyright holder. 15 | 16 | The above copyright notice and this permission notice need to be included 17 | in all copies or substantial portions of the software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /Structural/Adapter/AdapterCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../../../../gtest/include/gtest/gtest.h" 3 | #include "../../../../../gtest/include/gtest/internal/gtest-internal.h" 4 | #include "../../../../../gtest/include/gtest/gtest_pred_impl.h" 5 | 6 | struct Square 7 | { 8 | int side{ 0 }; 9 | 10 | 11 | explicit Square(const int side) 12 | : side(side) 13 | { 14 | } 15 | }; 16 | 17 | struct Rectangle 18 | { 19 | virtual int width() const = 0; 20 | virtual int height() const = 0; 21 | 22 | int area() const 23 | { 24 | return width() * height(); 25 | } 26 | }; 27 | 28 | struct SquareToRectangleAdapter : Rectangle 29 | { 30 | SquareToRectangleAdapter(const Square& square) 31 | : square(square) {} 32 | 33 | int width() const override 34 | { 35 | return square.side; 36 | } 37 | 38 | int height() const override 39 | { 40 | return square.side; 41 | } 42 | 43 | const Square& square; 44 | }; 45 | 46 | #include "gtest/gtest.h" 47 | 48 | //#include "helpers/iohelper.h" 49 | 50 | //#include "exercise.cpp" 51 | 52 | 53 | namespace 54 | { 55 | class Evaluate : public testing::Test 56 | { 57 | }; 58 | 59 | TEST_F(Evaluate, SimpleTest) 60 | { 61 | Square sq{ 11 }; 62 | SquareToRectangleAdapter adapter{ sq }; 63 | ASSERT_EQ(121, adapter.area()); 64 | } 65 | } 66 | 67 | int main(int ac, char* av[]) 68 | { 69 | testing::InitGoogleTest(&ac, av); 70 | return RUN_ALL_TESTS(); 71 | } -------------------------------------------------------------------------------- /Structural/Façade/Bloom.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "Window.h" 3 | #include "TextBuffer.h" 4 | #include "Console.h" 5 | using namespace std; 6 | 7 | int main(int ac, char* av[]) 8 | { 9 | // create a single window and show it 10 | //Window window("Test", 2560, 1440); 11 | //Window window("Test", 1280, 720); 12 | 13 | //// let's try to create a viewport + buffer 14 | //auto buffer = make_shared(40, 40); 15 | //buffer->add_string("One"); 16 | //buffer->add_string(string("Two")); 17 | //buffer->add_string(string("Three")); 18 | //buffer->add_string(string("Four")); 19 | //buffer->add_string(string("Five")); 20 | //window.buffers.push_back(buffer); 21 | //auto viewport = make_shared(buffer); 22 | //window.viewports.emplace_back(viewport); 23 | 24 | //auto viewport2 = make_shared(buffer, Size{ 40,40 }, Point{}, Point{ 45, 0 }); 25 | //window.viewports.emplace_back(viewport2); 26 | // 27 | //auto viewport3 = make_shared(buffer, Size{ 40,40 }, Point{}, Point{ 90, 0 }); 28 | //window.viewports.emplace_back(viewport3); 29 | 30 | //auto window = Console::instance().single("Test", 50, 30); 31 | auto window = Console::instance().multicolumn("Test", 2, 40, 40); 32 | 33 | for (size_t i = 0; i < 40; i++) 34 | { 35 | window->buffers[1]->add_string( 36 | string("This is line ") + boost::lexical_cast(i), 37 | (i % 2 == 0)); 38 | } 39 | 40 | window->Show(); 41 | return 0; 42 | } -------------------------------------------------------------------------------- /Structural/AdapterVisual/Geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | struct Point 6 | { 7 | int x, y; 8 | 9 | 10 | friend std::size_t hash_value(const Point& obj) 11 | { 12 | std::size_t seed = 0x725C686F; 13 | boost::hash_combine(seed, obj.x); 14 | boost::hash_combine(seed, obj.y); 15 | return seed; 16 | } 17 | }; 18 | 19 | struct Line 20 | { 21 | Point start, end; 22 | 23 | 24 | friend std::size_t hash_value(const Line& obj) 25 | { 26 | std::size_t seed = 0x719E6B16; 27 | boost::hash_combine(seed, obj.start); 28 | boost::hash_combine(seed, obj.end); 29 | return seed; 30 | } 31 | }; 32 | 33 | struct VectorObject 34 | { 35 | virtual std::vector::iterator begin() = 0; 36 | virtual std::vector::iterator end() = 0; 37 | }; 38 | 39 | struct VectorRectangle : VectorObject 40 | { 41 | VectorRectangle(int x, int y, int width, int height) 42 | { 43 | lines.emplace_back(Line{ Point{x,y}, Point{x + width,y} }); 44 | lines.emplace_back(Line{ Point{x + width,y}, Point{x+width, y+height} }); 45 | lines.emplace_back(Line{ Point{x,y}, Point{x,y+height} }); 46 | lines.emplace_back(Line{ Point{ x,y + height }, Point{ x + width, y + height } }); 47 | } 48 | 49 | std::vector::iterator begin() override { 50 | return lines.begin(); 51 | } 52 | std::vector::iterator end() override { 53 | return lines.end(); 54 | } 55 | private: 56 | std::vector lines; 57 | }; -------------------------------------------------------------------------------- /Creational/Creational/LSP.cpp: -------------------------------------------------------------------------------- 1 | // Objects in a program should be replaceable with instances of their subtypes 2 | // w/o altering the correctness of the program 3 | 4 | #include 5 | 6 | class Rectangle 7 | { 8 | protected: 9 | int width, height; 10 | public: 11 | Rectangle(const int width, const int height) 12 | : width{width}, height{height} { } 13 | 14 | int get_width() const { return width; } 15 | virtual void set_width(const int width) { this->width = width; } 16 | int get_height() const { return height; } 17 | virtual void set_height(const int height) { this->height = height; } 18 | 19 | int area() const { return width * height; } 20 | }; 21 | 22 | class Square : public Rectangle 23 | { 24 | public: 25 | Square(int size): Rectangle(size,size) {} 26 | void set_width(const int width) override { 27 | this->width = height = width; 28 | } 29 | void set_height(const int height) override { 30 | this->height = width = height; 31 | } 32 | }; 33 | 34 | struct RectangleFactory 35 | { 36 | static Rectangle create_rectangle(int w, int h); 37 | static Rectangle create_square(int size); 38 | }; 39 | 40 | void process(Rectangle& r) 41 | { 42 | int w = r.get_width(); 43 | r.set_height(10); 44 | 45 | std::cout << "expected area = " << (w * 10) 46 | << ", got " << r.area() << std::endl; 47 | } 48 | 49 | int main342342() 50 | { 51 | Rectangle r{ 3, 4 }; 52 | process(r); 53 | 54 | Square sq{ 5 }; 55 | process(sq); 56 | 57 | getchar(); 58 | return 0; 59 | } -------------------------------------------------------------------------------- /Structural/PingPongService/PingPongService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dnx451;dnxcore50 5 | PingPongService 6 | Exe 7 | PingPongService 8 | 9 | 10 | 11 | 12 | 13 | 14 | Never 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Structural/Composite/CompositeCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct ContainsIntegers 8 | { 9 | virtual int sum() = 0; 10 | }; 11 | 12 | struct SingleValue : ContainsIntegers 13 | { 14 | int value{ 0 }; 15 | 16 | SingleValue() = default; 17 | 18 | explicit SingleValue(const int value) 19 | : value{value} 20 | { 21 | } 22 | 23 | int sum() override { 24 | return value; 25 | } 26 | }; 27 | 28 | struct ManyValues : vector, ContainsIntegers 29 | { 30 | void add(const int value) 31 | { 32 | push_back(value); 33 | } 34 | 35 | int sum() override { 36 | return accumulate(begin(), end(), 0); 37 | } 38 | }; 39 | 40 | int sum(const vector items) 41 | { 42 | int result{0}; 43 | for (auto item : items) 44 | result += item->sum(); 45 | return result; 46 | } 47 | 48 | #include "gtest/gtest.h" 49 | 50 | //#include "helpers/iohelper.h" 51 | 52 | //#include "exercise.cpp" 53 | 54 | namespace 55 | { 56 | class Evaluate : public testing::Test 57 | { 58 | }; 59 | 60 | TEST_F(Evaluate, SimpleTest) 61 | { 62 | SingleValue single_value{ 11 }; 63 | ManyValues other_values; 64 | other_values.add(22); 65 | other_values.add(33); 66 | ASSERT_EQ(66, sum({ &single_value, &other_values })); 67 | } 68 | 69 | } // namespace 70 | 71 | int main(int ac, char* av[]) 72 | { 73 | testing::InitGoogleTest(&ac, av); 74 | return RUN_ALL_TESTS(); 75 | } -------------------------------------------------------------------------------- /Behavioral/Mediator/MediatorCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct IParticipant 6 | { 7 | virtual void notify(IParticipant* sender, int value) = 0; 8 | }; 9 | 10 | struct Mediator 11 | { 12 | vector participants; 13 | void say(IParticipant* sender, int value) 14 | { 15 | for (auto p : participants) 16 | p->notify(sender, value); 17 | } 18 | }; 19 | 20 | struct Participant : IParticipant 21 | { 22 | int value{0}; 23 | Mediator& mediator; 24 | 25 | Participant(Mediator &mediator) : mediator(mediator) 26 | { 27 | mediator.participants.push_back(this); 28 | } 29 | 30 | void notify(IParticipant *sender, int value) override { 31 | if (sender != this) 32 | this->value += value; 33 | } 34 | 35 | void say(int value) 36 | { 37 | mediator.say(this, value); 38 | } 39 | }; 40 | 41 | #include "gtest/gtest.h" 42 | #include "helpers/iohelper.h" 43 | 44 | #include "exercise.cpp" 45 | 46 | namespace { 47 | 48 | class Evaluate : public ::testing::Test {}; 49 | 50 | TEST_F(Evaluate, LongMediationTest) { 51 | Mediator m; 52 | Participant p1{m}, p2{m}; 53 | 54 | ASSERT_EQ(0, p1.value); 55 | ASSERT_EQ(0, p2.value); 56 | 57 | p1.say(2); 58 | 59 | ASSERT_EQ(0, p1.value); 60 | ASSERT_EQ(2, p2.value); 61 | 62 | p2.say(4); 63 | 64 | ASSERT_EQ(4, p1.value); 65 | ASSERT_EQ(2, p2.value); 66 | } 67 | 68 | } // namespace 69 | -------------------------------------------------------------------------------- /Behavioral/Command/CommandCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct Command 6 | { 7 | enum Action { deposit, withdraw } action; 8 | int amount{0}; 9 | bool success{false}; 10 | }; 11 | 12 | struct Account 13 | { 14 | int balance{0}; 15 | 16 | void process(Command& cmd) 17 | { 18 | switch (cmd.action) 19 | { 20 | case Command::deposit: 21 | balance += cmd.amount; 22 | cmd.success = true; 23 | break; 24 | case Command::withdraw: 25 | cmd.success = (balance >= cmd.amount); 26 | if (cmd.success) balance -= cmd.amount; 27 | break; 28 | } 29 | } 30 | }; 31 | 32 | #include "gtest/gtest.h" 33 | 34 | //#include "helpers/iohelper.h" 35 | 36 | //#include "exercise.cpp" 37 | 38 | namespace 39 | { 40 | class Evaluate : public testing::Test 41 | { 42 | public: 43 | }; 44 | 45 | TEST_F(Evaluate, LotsOfAccountTests) 46 | { 47 | Account a; 48 | Command command{Command::deposit, 100}; 49 | a.process(command); 50 | 51 | ASSERT_EQ(100, a.balance); 52 | ASSERT_TRUE(command.success); 53 | 54 | command = Command{Command::withdraw, 50}; 55 | a.process(command); 56 | 57 | ASSERT_EQ(50, a.balance); 58 | ASSERT_TRUE(command.success); 59 | 60 | command = Command{Command::withdraw, 150}; 61 | a.process(command); 62 | 63 | ASSERT_EQ(50, a.balance); 64 | ASSERT_FALSE(command.success); 65 | } 66 | } // namespace 67 | 68 | int main(int ac, char* av[]) 69 | { 70 | testing::InitGoogleTest(&ac, av); 71 | return RUN_ALL_TESTS(); 72 | } -------------------------------------------------------------------------------- /Structural/Bridge/BridgeCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../../../../../gtest/include/gtest/gtest.h" 5 | using namespace std; 6 | 7 | struct Renderer 8 | { 9 | virtual string what_to_render_as() const = 0; 10 | }; 11 | 12 | struct Shape 13 | { 14 | string name; 15 | const Renderer& renderer; 16 | 17 | Shape(const Renderer& renderer): renderer{renderer} { 18 | } 19 | 20 | string str() const 21 | { 22 | ostringstream oss; 23 | oss << "Drawing " << name << " as " 24 | << renderer.what_to_render_as(); 25 | return oss.str(); 26 | } 27 | }; 28 | 29 | struct Triangle : Shape 30 | { 31 | explicit Triangle(const Renderer& renderer) 32 | : Shape{renderer} 33 | { 34 | name = "Triangle"; 35 | } 36 | }; 37 | 38 | struct Square : Shape 39 | { 40 | explicit Square(const Renderer& renderer) 41 | : Shape{renderer} 42 | { 43 | name = "Square"; 44 | } 45 | }; 46 | 47 | struct RasterRenderer : Renderer 48 | { 49 | string what_to_render_as() const override 50 | { 51 | return "pixels"; 52 | } 53 | }; 54 | 55 | struct VectorRenderer : Renderer 56 | { 57 | string what_to_render_as() const override 58 | { 59 | return "lines"; 60 | } 61 | }; 62 | 63 | //#include "gtest/gtest.h" 64 | 65 | //#include "helpers/iohelper.h" 66 | 67 | //#include "exercise.cpp" 68 | 69 | namespace 70 | { 71 | class Evaluate : public testing::Test 72 | { 73 | }; 74 | 75 | TEST_F(Evaluate, SimpleTest) 76 | { 77 | ASSERT_EQ("Drawing Square as lines", 78 | Square{VectorRenderer{}}.str()) 79 | } 80 | 81 | } // namespace -------------------------------------------------------------------------------- /Structural/Adapter/adapter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | #include 9 | 10 | void stack_and_vector() 11 | { 12 | stack> s; 13 | s.push(123); 14 | int x = s.top(); 15 | s.pop(); 16 | } 17 | 18 | class String 19 | { 20 | string s; 21 | public: 22 | String(const string& s) : s{s} 23 | { 24 | } 25 | 26 | String to_lower_copy() const 27 | { 28 | return{ boost::to_lower_copy(s) }; 29 | //string ss{ s }; 30 | //boost::to_lower(ss); 31 | //return { ss }; 32 | } 33 | 34 | vector split(const string& delimeter = " ") const 35 | { 36 | vector parts; 37 | boost::split(parts, s, boost::is_any_of(delimeter.c_str()), 38 | boost::token_compress_on); 39 | return vector(parts.begin(), parts.end()); 40 | } 41 | 42 | size_t get_length() const { return s.length(); } 43 | 44 | __declspec(property(get = get_length)) size_t length; 45 | }; 46 | 47 | int main() 48 | { 49 | // lowercase then split 50 | // start on lowercase 's' 51 | //String s{ "Hello World" }; 52 | 53 | /*vector parts; 54 | boost::to_lower(s); 55 | boost::split(parts, s, boost::is_any_of(" ")); 56 | for (const auto& p : parts) 57 | cout << "<" << p << ">" << endl;*/ 58 | 59 | String s{ u8"Hello World" }; 60 | auto parts = s.to_lower_copy().split(); 61 | for (const auto& p : parts) 62 | { 63 | // portable 64 | cout << p.get_length() << endl; 65 | // not portable 66 | cout << p.length << endl; 67 | } 68 | 69 | getchar(); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /Structural/Façade/Console.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "Window.h" 6 | #include "TextBuffer.h" 7 | using namespace std; 8 | 9 | class Console 10 | { 11 | public: 12 | static Console& instance() 13 | { 14 | static Console console; 15 | return console; 16 | } 17 | 18 | vector> windows; 19 | 20 | // cannot make this static 21 | shared_ptr single(const string& title, uint8_t charsWide, uint8_t charsHigh) 22 | { 23 | auto w = make_shared(title, charsWide * charWidth, charsHigh * charHeight); 24 | auto buffer = make_shared(charsWide, charsHigh); 25 | w->buffers.push_back(buffer); 26 | auto viewport = make_shared(buffer); 27 | w->viewports.push_back(viewport); 28 | windows.push_back(w); 29 | return w; 30 | } 31 | 32 | shared_ptr multicolumn(const string& title, uint8_t columnCount, uint8_t columnWidth, uint8_t charsHigh) 33 | { 34 | auto w = make_shared(title, columnCount * columnWidth * charWidth, charsHigh * charHeight); 35 | for (uint8_t c = 0; c < columnCount; ++c) 36 | { 37 | auto buffer = make_shared(columnWidth, charsHigh); 38 | w->buffers.push_back(buffer); 39 | auto viewport = make_shared(buffer, buffer->get_size(), Point{}, Point{ columnWidth*c, 0 }); 40 | w->viewports.push_back(viewport); 41 | windows.push_back(w); 42 | } 43 | return w; 44 | } 45 | 46 | private: 47 | const int charWidth = 10, charHeight = 14; 48 | Console(){} 49 | Console(Console const&) = delete; 50 | void operator=(Console const&) = delete; 51 | }; 52 | -------------------------------------------------------------------------------- /Creational/Creational/BoostDI.cpp: -------------------------------------------------------------------------------- 1 | #include "di.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using std::make_unique; 7 | using std::make_shared; 8 | 9 | struct Engine 10 | { 11 | float volume = 5; 12 | int horse_power = 400; 13 | 14 | friend std::ostream& operator<<(std::ostream& os, const Engine& obj) 15 | { 16 | return os 17 | << "volume: " << obj.volume 18 | << " horse_power: " << obj.horse_power; 19 | } 20 | }; 21 | 22 | struct ILogger 23 | { 24 | virtual ~ILogger() 25 | { 26 | } 27 | 28 | virtual void Log(const std::string& s) = 0; 29 | }; 30 | 31 | struct ConsoleLogger : ILogger 32 | { 33 | ConsoleLogger() 34 | { 35 | } 36 | 37 | void Log(const std::string& s) override 38 | { 39 | std::cout << "LOG:" << s.c_str() << std::endl; 40 | } 41 | }; 42 | 43 | struct Car 44 | { 45 | std::unique_ptr engine; 46 | std::shared_ptr logger; 47 | 48 | Car(std::unique_ptr engine, const std::shared_ptr& logger) 49 | : engine{move(engine)}, 50 | logger{logger} 51 | { 52 | logger->Log("making a car"); 53 | } 54 | 55 | friend std::ostream& operator<<(std::ostream& os, const Car& obj) 56 | { 57 | return os << "car with engine: " << *obj.engine; 58 | } 59 | }; 60 | 61 | int main123() 62 | { 63 | // manual 64 | auto logger = make_shared(); 65 | auto c = make_shared(make_unique(),logger); 66 | 67 | using namespace boost; 68 | auto injector = di::make_injector( 69 | di::bind().to() 70 | ); 71 | auto car = injector.create>(); 72 | 73 | std::cout << *car << std::endl; 74 | 75 | getchar(); 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /Creational/Creational/MaybeMonad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | struct Address { 11 | string* house_name = nullptr; 12 | }; 13 | 14 | struct Person { 15 | Address* address = nullptr; 16 | }; 17 | 18 | template struct Maybe; 19 | template Maybe maybe(T* context) 20 | { 21 | return Maybe(context); 22 | } 23 | 24 | template 25 | struct Maybe { 26 | T* context; 27 | 28 | Maybe(T *context) : context(context) { } 29 | 30 | template 31 | auto With(TFunc evaluator) 32 | { 33 | /*if (context == nullptr) 34 | return Maybe::type>(nullptr); 35 | return maybe(evaluator(context));*/ 36 | return context != nullptr ? maybe(evaluator(context)) : nullptr; 37 | }; 38 | 39 | template 40 | auto Do(TFunc action) 41 | { 42 | if (context != nullptr) action(context); 43 | return *this; 44 | } 45 | }; 46 | 47 | void print_house_name(Person* p) 48 | { 49 | // if (p != nullptr && p->address != nullptr && p->address->house_name != nullptr) 50 | // cout << *p->address->house_name << endl; 51 | auto z = maybe(p) 52 | .With([](auto x) { return x->address; }) 53 | .With([](auto x) { return x->house_name; }) 54 | .Do([](auto x) { cout << *x << endl; }); 55 | } 56 | 57 | 58 | 59 | int main_57576() 60 | { 61 | Person p; 62 | p.address = new Address; 63 | p.address->house_name = new string("name"); 64 | print_house_name(&p); 65 | 66 | delete p.address->house_name; 67 | delete p.address; 68 | 69 | getchar(); 70 | return 0; 71 | } -------------------------------------------------------------------------------- /Creational/Creational/Person.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class PersonBuilder; 6 | 7 | class Person 8 | { 9 | // address 10 | std::string street_address, post_code, city; 11 | 12 | // employment 13 | std::string company_name, position; 14 | int annual_income = 0; 15 | 16 | Person() 17 | { 18 | std::cout << "Person created\n"; 19 | } 20 | 21 | public: 22 | ~Person() 23 | { 24 | std::cout << "Person destroyed\n"; 25 | } 26 | 27 | static PersonBuilder create(); 28 | 29 | Person(Person&& other) 30 | : street_address{move(other.street_address)}, 31 | post_code{move(other.post_code)}, 32 | city{move(other.city)}, 33 | company_name{move(other.company_name)}, 34 | position{move(other.position)}, 35 | annual_income{other.annual_income} 36 | { 37 | } 38 | 39 | Person& operator=(Person&& other) 40 | { 41 | if (this == &other) 42 | return *this; 43 | street_address = move(other.street_address); 44 | post_code = move(other.post_code); 45 | city = move(other.city); 46 | company_name = move(other.company_name); 47 | position = move(other.position); 48 | annual_income = other.annual_income; 49 | return *this; 50 | } 51 | 52 | friend std::ostream& operator<<(std::ostream& os, const Person& obj) 53 | { 54 | return os 55 | << "street_address: " << obj.street_address 56 | << " post_code: " << obj.post_code 57 | << " city: " << obj.city 58 | << " company_name: " << obj.company_name 59 | << " position: " << obj.position 60 | << " annual_income: " << obj.annual_income; 61 | } 62 | 63 | friend class PersonBuilder; 64 | friend class PersonAddressBuilder; 65 | friend class PersonJobBuilder; 66 | }; 67 | -------------------------------------------------------------------------------- /Structural/Bridge/bridge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "Person.h" 5 | using namespace std; 6 | 7 | // two classes of objects 8 | 9 | // Renderers - determine how an object is drawn 10 | // Shapes - determine what to draw 11 | 12 | struct Renderer 13 | { 14 | virtual void render_circle(float x, float y, float radius) = 0; 15 | }; 16 | 17 | struct VectorRenderer : Renderer 18 | { 19 | void render_circle(float x, float y, float radius) override 20 | { 21 | cout << "Rasterizing circle of radius " << radius << endl; 22 | } 23 | }; 24 | 25 | struct RasterRenderer : Renderer 26 | { 27 | void render_circle(float x, float y, float radius) override 28 | { 29 | cout << "Drawing a vector circle of radius " << radius << endl; 30 | } 31 | }; 32 | 33 | struct Shape 34 | { 35 | protected: 36 | Renderer& renderer; 37 | Shape(Renderer& renderer) : renderer{ renderer } {} 38 | public: 39 | virtual void draw() = 0; // implementation specific 40 | virtual void resize(float factor) = 0; // abstraction specific 41 | }; 42 | 43 | struct Circle : Shape 44 | { 45 | float x, y, radius; 46 | 47 | void draw() override 48 | { 49 | renderer.render_circle(x, y, radius); 50 | } 51 | 52 | void resize(float factor) override 53 | { 54 | radius *= factor; 55 | } 56 | 57 | Circle(Renderer& renderer, float x, float y, float radius) 58 | : Shape{renderer}, 59 | x{x}, 60 | y{y}, 61 | radius{radius} 62 | { 63 | } 64 | }; 65 | 66 | void bridge() 67 | { 68 | RasterRenderer rr; 69 | Circle raster_circle{ rr, 5,5,5 }; 70 | raster_circle.draw(); 71 | raster_circle.resize(2); 72 | raster_circle.draw(); 73 | } 74 | 75 | int main() 76 | { 77 | 78 | 79 | Person p; 80 | p.greet(); 81 | 82 | getchar(); 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /Behavioral/Iterator/IteratorCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | template 6 | struct Node 7 | { 8 | T value; 9 | Node *left{nullptr}, *right{nullptr}, *parent{nullptr}; 10 | 11 | Node(T value) : value(value) {} 12 | 13 | Node(T value, Node *left, Node *right) : value(value), left(left), right(right) { 14 | left->parent = right->parent = this; 15 | } 16 | 17 | void preorder_traversal_impl(Node* current, vector*>& result) 18 | { 19 | result.push_back(current); 20 | if (current->left) 21 | { 22 | preorder_traversal_impl(current->left, result); 23 | } 24 | if (current->right) 25 | { 26 | preorder_traversal_impl(current->right, result); 27 | } 28 | } 29 | 30 | // traverse the node and its children preorder 31 | // and put all the results into `result` 32 | void preorder_traversal(vector*>& result) 33 | { 34 | preorder_traversal_impl(this, result); 35 | } 36 | }; 37 | 38 | #include "gtest/gtest.h" 39 | 40 | //#include "helpers/iohelper.h" 41 | 42 | //#include "exercise.cpp" 43 | 44 | namespace { 45 | 46 | class Evaluate : public ::testing::Test {}; 47 | 48 | TEST_F(Evaluate, ExampleTest) { 49 | Node c{'c'}; 50 | Node d{'d'}; 51 | Node e{'e'}; 52 | Node b{'b', &c, &d}; 53 | Node a{'a', &b, &e}; 54 | 55 | vector*> result; 56 | a.preorder_traversal(result); 57 | 58 | ostringstream oss; 59 | for (auto n : result) 60 | oss << n->value; 61 | ASSERT_EQ("abcde", oss.str()); 62 | } 63 | 64 | } // namespace 65 | 66 | int main(int ac, char* av[]) 67 | { 68 | //::testing::GTEST_FLAG(catch_exceptions) = false; 69 | testing::InitGoogleTest(&ac, av); 70 | return RUN_ALL_TESTS(); 71 | } -------------------------------------------------------------------------------- /Behavioral/Visitor/visitor_reflective.cpp: -------------------------------------------------------------------------------- 1 | // visitor examples for design patterns c++ book 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct Expression 8 | { 9 | virtual ~Expression() = default; 10 | }; 11 | 12 | struct DoubleExpression : Expression 13 | { 14 | double value; 15 | explicit DoubleExpression(const double value) 16 | : value{ value } {} 17 | }; 18 | 19 | struct AdditionExpression : Expression 20 | { 21 | Expression *left, *right; 22 | 23 | AdditionExpression(Expression* const left, Expression* const right) 24 | : left{ left }, right{ right } {} 25 | 26 | ~AdditionExpression() 27 | { 28 | delete left; 29 | delete right; 30 | } 31 | }; 32 | 33 | struct ExpressionPrinter 34 | { 35 | /*void print(DoubleExpression *de, ostringstream& oss) const 36 | { 37 | oss << de->value; 38 | } 39 | void print(AdditionExpression *ae, ostringstream& oss) const 40 | { 41 | oss << "("; 42 | print(ae->left, oss); 43 | oss << "+"; 44 | print(ae->right, oss); 45 | oss << ")"; 46 | }*/ 47 | ostringstream oss; 48 | 49 | void print(Expression *e) 50 | { 51 | if (auto de = dynamic_cast(e)) 52 | { 53 | oss << de->value; 54 | } 55 | else if (auto ae = dynamic_cast(e)) 56 | { 57 | oss << "("; 58 | print(ae->left); 59 | oss << "+"; 60 | print(ae->right); 61 | oss << ")"; 62 | } 63 | } 64 | 65 | string str() const { return oss.str(); } 66 | }; 67 | 68 | void main_3_() 69 | { 70 | auto e = new AdditionExpression{ 71 | new DoubleExpression{ 1 }, 72 | new AdditionExpression{ 73 | new DoubleExpression{ 2 }, 74 | new DoubleExpression{ 3 } 75 | } 76 | }; 77 | ostringstream oss; 78 | //e->print(oss); 79 | ExpressionPrinter ep; 80 | ep.print(e); 81 | cout << ep.str() << endl; 82 | } -------------------------------------------------------------------------------- /Behavioral/Mediator/soccer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | struct Game; 5 | using namespace std; 6 | 7 | #include 8 | using namespace boost::signals2; 9 | 10 | struct EventData 11 | { 12 | virtual ~EventData() = default; 13 | virtual void print() const = 0; 14 | }; 15 | 16 | struct Player; 17 | struct PlayerScoredData : EventData 18 | { 19 | string player_name; 20 | int goals_scored_so_far; 21 | 22 | PlayerScoredData(const string& player_name, const int goals_scored_so_far) 23 | : player_name(player_name), 24 | goals_scored_so_far(goals_scored_so_far) 25 | { 26 | } 27 | 28 | void print() const override 29 | { 30 | cout << player_name << " has scored! (their " 31 | << goals_scored_so_far << " goal)" << "\n"; 32 | } 33 | }; 34 | 35 | struct Game 36 | { 37 | signal events; // observer 38 | }; 39 | 40 | struct Player 41 | { 42 | string name; 43 | int goals_scored = 0; 44 | Game& game; 45 | 46 | 47 | Player(const string& name, Game& game) 48 | : name(name), 49 | game(game) 50 | { 51 | } 52 | 53 | void score() 54 | { 55 | goals_scored++; 56 | PlayerScoredData ps{name, goals_scored}; 57 | game.events(&ps); 58 | } 59 | }; 60 | 61 | struct Coach 62 | { 63 | Game& game; 64 | 65 | explicit Coach(Game& game) 66 | : game(game) 67 | { 68 | // celebrate if player has scored <3 goals 69 | game.events.connect([](EventData* e) 70 | { 71 | PlayerScoredData* ps = dynamic_cast(e); 72 | if (ps && ps->goals_scored_so_far < 3) 73 | { 74 | cout << "coach says: well done, " << ps->player_name << "\n"; 75 | } 76 | }); 77 | } 78 | }; 79 | 80 | int main() 81 | { 82 | Game game; 83 | Player player{ "Sam", game }; 84 | Coach coach{ game }; 85 | 86 | player.score(); 87 | player.score(); 88 | player.score(); // ignored by coach 89 | 90 | getchar(); 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /Creational/Creational/GroovyStyle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace html { 6 | struct Tag 7 | { 8 | std::string name; 9 | std::string text; 10 | std::vector children; 11 | std::vector> attributes; 12 | 13 | friend std::ostream& operator<<(std::ostream& os, const Tag& tag) 14 | { 15 | os << "<" << tag.name; 16 | 17 | for (const auto& att : tag.attributes) 18 | os << " " << att.first << "=\"" << att.second << "\""; 19 | 20 | if (tag.children.size() == 0 && tag.text.length() == 0) 21 | { 22 | os << "/>" << std::endl; 23 | } 24 | else 25 | { 26 | os << ">" << std::endl; 27 | 28 | if (tag.text.length()) 29 | os << tag.text << std::endl; 30 | 31 | for (const auto& child : tag.children) 32 | os << child; 33 | 34 | os << "" << std::endl; 35 | } 36 | 37 | return os; 38 | } 39 | protected: 40 | 41 | Tag(const std::string& name, const std::string& text) 42 | : name{name}, 43 | text{text} 44 | { 45 | } 46 | 47 | 48 | Tag(const std::string& name, const std::vector& children) 49 | : name{name}, 50 | children{children} 51 | { 52 | } 53 | }; 54 | 55 | struct P : Tag 56 | { 57 | explicit P(const std::string& text) 58 | : Tag{"p", text} 59 | { 60 | } 61 | 62 | P(std::initializer_list children) 63 | : Tag("p", children) 64 | { 65 | } 66 | 67 | }; 68 | 69 | struct IMG : Tag 70 | { 71 | explicit IMG(const std::string& url) 72 | : Tag{"img", ""} 73 | { 74 | attributes.emplace_back(make_pair("src", url)); 75 | } 76 | }; 77 | } 78 | 79 | int main1() 80 | { 81 | using namespace html; 82 | 83 | std::cout << 84 | 85 | P { 86 | IMG {"http://pokemon.com/pikachu.png"} 87 | } 88 | 89 | << std::endl; 90 | 91 | getchar(); 92 | return 0; 93 | } -------------------------------------------------------------------------------- /Structural/AdapterVisual/stdafx.h: -------------------------------------------------------------------------------- 1 | 2 | // stdafx.h : include file for standard system include files, 3 | // or project specific include files that are used frequently, 4 | // but are changed infrequently 5 | 6 | #pragma once 7 | 8 | #ifndef VC_EXTRALEAN 9 | #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 10 | #endif 11 | 12 | #include "targetver.h" 13 | 14 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit 15 | #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // remove support for MFC controls in dialogs 16 | 17 | // turns off MFC's hiding of some common and often safely ignored warning messages 18 | #define _AFX_ALL_WARNINGS 19 | 20 | #include // MFC core and standard components 21 | #include // MFC extensions 22 | 23 | 24 | #include // MFC Automation classes 25 | 26 | 27 | 28 | #ifndef _AFX_NO_OLE_SUPPORT 29 | #include // MFC support for Internet Explorer 4 Common Controls 30 | #endif 31 | #ifndef _AFX_NO_AFXCMN_SUPPORT 32 | #include // MFC support for Windows Common Controls 33 | #endif // _AFX_NO_AFXCMN_SUPPORT 34 | 35 | #include // MFC support for ribbons and control bars 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | #ifdef _UNICODE 46 | #if defined _M_IX86 47 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 48 | #elif defined _M_X64 49 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 50 | #else 51 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 52 | #endif 53 | #endif 54 | 55 | 56 | -------------------------------------------------------------------------------- /Structural/Composite/composite.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | #include 7 | #include 8 | using namespace boost::accumulators; 9 | 10 | // 2 + (3+4) 11 | struct Expression 12 | { 13 | virtual double eval() = 0; 14 | virtual void collect(vector& v) = 0; 15 | }; 16 | 17 | struct Literal : Expression 18 | { 19 | double value; 20 | 21 | explicit Literal(const double value) 22 | : value{value} 23 | { 24 | } 25 | 26 | double eval() override 27 | { 28 | return value; 29 | } 30 | 31 | void collect(vector& v) override 32 | { 33 | v.push_back(value); 34 | } 35 | }; 36 | 37 | struct AdditionExpression : Expression 38 | { 39 | shared_ptr left, right; 40 | 41 | AdditionExpression(const shared_ptr& expression, const shared_ptr& expression1) 42 | : left{expression}, 43 | right{expression1} 44 | { 45 | } 46 | 47 | double eval() override 48 | { 49 | return left->eval() + right->eval(); 50 | } 51 | 52 | void collect(vector& v) override 53 | { 54 | left->collect(v); 55 | right->collect(v); 56 | } 57 | }; 58 | 59 | int main__3(int ac, char* av) 60 | { 61 | AdditionExpression sum{ 62 | make_shared(2), 63 | make_shared( 64 | make_shared(3), 65 | make_shared(4) 66 | ) 67 | }; 68 | cout << "2+(3+4) = " << sum.eval() << endl; 69 | 70 | vector v; 71 | sum.collect(v); 72 | for (auto x : v) 73 | cout << x << "\t"; 74 | cout << endl; 75 | 76 | vector values{ 1,2,3,4 }; 77 | double s = 0; 78 | for (auto x : values) s += x; 79 | cout << "average is " << (s / values.size()) << endl; 80 | 81 | accumulator_set> acc; 82 | for (auto x : values) acc(x); 83 | cout << "average is " << mean(acc) << endl; 84 | 85 | getchar(); 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /Structural/Proxy/ProxyCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | class Person 11 | { 12 | friend class ResponsiblePerson; 13 | int age; 14 | public: 15 | Person(int age) : age(age) {} 16 | 17 | int get_age() const { return age; } 18 | void set_age(int age) { this->age=age; } 19 | 20 | string drink() const { return "drinking"; } 21 | string drive() const { return "driving"; } 22 | string drink_and_drive() const { return "driving while drunk"; } 23 | }; 24 | 25 | struct ResponsiblePerson 26 | { 27 | ResponsiblePerson(const Person &person) : person(person) {} 28 | 29 | int get_age() const { return person.age; } 30 | void set_age(int value) { person.age = value; } 31 | 32 | string drink() const { 33 | if (get_age() >= 18) 34 | return person.drink(); 35 | else return "too young"; 36 | } 37 | 38 | string drive() const { 39 | if (get_age() >= 16) 40 | return person.drive(); 41 | else return "too young"; 42 | } 43 | 44 | string drink_and_drive() const 45 | { 46 | return "dead"; 47 | } 48 | 49 | private: 50 | Person person; 51 | }; 52 | 53 | 54 | 55 | #include "gtest/gtest.h" 56 | 57 | //#include "helpers/iohelper.h" 58 | 59 | //#include "exercise.cpp" 60 | 61 | namespace 62 | { 63 | class Evaluate : public testing::Test 64 | { 65 | public: 66 | }; 67 | 68 | TEST_F(Evaluate, BaselineTest) 69 | { 70 | Person p{10}; 71 | ResponsiblePerson rp{p}; 72 | 73 | ASSERT_EQ("too young", rp.drive()); 74 | ASSERT_EQ("too young", rp.drink()); 75 | ASSERT_EQ("dead", rp.drink_and_drive()); 76 | 77 | rp.set_age(20); 78 | 79 | ASSERT_EQ("driving", rp.drive()); 80 | ASSERT_EQ("drinking", rp.drink()); 81 | ASSERT_EQ("dead", rp.drink_and_drive()); 82 | } 83 | 84 | } // namespace 85 | 86 | int main(int ac, char* av[]) 87 | { 88 | testing::InitGoogleTest(&ac, av); 89 | return RUN_ALL_TESTS(); 90 | } -------------------------------------------------------------------------------- /Behavioral/State/StateCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | class CombinationLock 7 | { 8 | vector combination; 9 | int digits_entered{0}; 10 | bool failed{false}; 11 | 12 | void reset() 13 | { 14 | status = "LOCKED"; 15 | digits_entered = 0; 16 | failed = false; 17 | } 18 | public: 19 | string status; 20 | 21 | CombinationLock(const vector &combination) : combination(combination) { 22 | reset(); 23 | } 24 | 25 | void enter_digit(int digit) 26 | { 27 | if (status == "LOCKED") status = ""; 28 | status += to_string(digit); 29 | if (combination[digits_entered] != digit) 30 | { 31 | failed = true; 32 | } 33 | digits_entered++; 34 | 35 | if (digits_entered == combination.size()) 36 | status = failed ? "ERROR" : "OPEN"; 37 | } 38 | }; 39 | 40 | #include "gtest/gtest.h" 41 | 42 | //#include "helpers/iohelper.h" 43 | 44 | //#include "exercise.cpp" 45 | 46 | namespace { 47 | 48 | class Evaluate : public ::testing::Test {}; 49 | 50 | TEST_F(Evaluate, TestSuccess) 51 | { 52 | CombinationLock cl({1,2,3}); 53 | ASSERT_EQ("LOCKED", cl.status); 54 | 55 | cl.enter_digit(1); 56 | ASSERT_EQ("1", cl.status); 57 | 58 | cl.enter_digit(2); 59 | ASSERT_EQ("12", cl.status); 60 | 61 | cl.enter_digit(3); 62 | ASSERT_EQ("OPEN", cl.status); 63 | } 64 | 65 | TEST_F(Evaluate, TestFailure) 66 | { 67 | CombinationLock cl({1,2,3}); 68 | ASSERT_EQ("LOCKED", cl.status); 69 | 70 | cl.enter_digit(1); 71 | ASSERT_EQ("1", cl.status); 72 | 73 | cl.enter_digit(2); 74 | ASSERT_EQ("12", cl.status); 75 | 76 | cl.enter_digit(5); 77 | ASSERT_EQ("ERROR", cl.status); 78 | } 79 | 80 | } // namespace 81 | 82 | int main(int ac, char* av[]) 83 | { 84 | //::testing::GTEST_FLAG(catch_exceptions) = false; 85 | testing::InitGoogleTest(&ac, av); 86 | return RUN_ALL_TESTS(); 87 | } -------------------------------------------------------------------------------- /Structural/Flyweight/FlyweightCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | using namespace std; 11 | 12 | struct Sentence 13 | { 14 | struct WordToken 15 | { 16 | bool capitalize; 17 | }; 18 | 19 | vector words; 20 | map tokens; 21 | 22 | Sentence(const string& text) 23 | { 24 | istringstream iss{text}; 25 | words = vector(istream_iterator{iss}, 26 | istream_iterator{}); 27 | } 28 | 29 | WordToken& operator[](size_t index) 30 | { 31 | tokens[index] = WordToken{}; 32 | return tokens[index]; 33 | } 34 | 35 | string str() const 36 | { 37 | vector ws; 38 | for (size_t i = 0; i < words.size(); ++i) 39 | { 40 | string w = words[i]; 41 | auto t = tokens.find(i); 42 | if (t != tokens.end() && t->second.capitalize) 43 | { 44 | // note: the annotation on ::toupper() below is only required 45 | // for GCC; other compilers work fine without it 46 | transform(w.begin(), w.end(), w.begin(), (int (&)(int)) toupper); 47 | } 48 | ws.push_back(w); 49 | } 50 | 51 | ostringstream oss; 52 | for (size_t i = 0; i < ws.size(); ++i) 53 | { 54 | oss << ws[i]; 55 | if (i+1 != ws.size()) oss << " "; 56 | } 57 | return oss.str(); 58 | } 59 | }; 60 | 61 | #include "gtest/gtest.h" 62 | 63 | //#include "helpers/iohelper.h" 64 | 65 | //#include "exercise.cpp" 66 | 67 | namespace 68 | { 69 | class Evaluate : public testing::Test 70 | { 71 | public: 72 | }; 73 | 74 | TEST_F(Evaluate, BaselineTest) 75 | { 76 | Sentence s{"alpha beta gamma"}; 77 | s[0].capitalize = s[2].capitalize = false; 78 | s[1].capitalize = true; 79 | ASSERT_EQ("alpha BETA gamma", s.str()); 80 | } 81 | 82 | } // namespace 83 | 84 | int main(int ac, char* av[]) 85 | { 86 | testing::InitGoogleTest(&ac, av); 87 | return RUN_ALL_TESTS(); 88 | } -------------------------------------------------------------------------------- /Behavioral/Strategy/strategy_static.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | enum class OutputFormat 9 | { 10 | Markdown, 11 | Html 12 | }; 13 | 14 | struct ListStrategy 15 | { 16 | virtual ~ListStrategy() = default; 17 | virtual void add_list_item(ostringstream& oss, const string& item) = 0; 18 | virtual void start(ostringstream& oss) = 0; 19 | virtual void end(ostringstream& oss) = 0; 20 | }; 21 | 22 | struct MarkdownListStrategy : ListStrategy 23 | { 24 | void start(ostringstream& oss) override 25 | { 26 | } 27 | 28 | void end(ostringstream& oss) override 29 | { 30 | } 31 | 32 | void add_list_item(ostringstream& oss, const string& item) override 33 | { 34 | oss << " * " << item << endl; 35 | } 36 | }; 37 | 38 | struct HtmlListStrategy : ListStrategy 39 | { 40 | void start(ostringstream& oss) override 41 | { 42 | oss << "
    " << endl; 43 | } 44 | 45 | void end(ostringstream& oss) override 46 | { 47 | oss << "
" << endl; 48 | } 49 | 50 | void add_list_item(ostringstream& oss, const string& item) override 51 | { 52 | oss << "
  • " << item << "
  • " << endl; 53 | } 54 | }; 55 | 56 | template 57 | struct TextProcessor 58 | { 59 | void clear() 60 | { 61 | oss.str(""); 62 | oss.clear(); 63 | } 64 | void append_list(const vector items) 65 | { 66 | list_strategy.start(oss); 67 | for (auto& item : items) 68 | list_strategy.add_list_item(oss, item); 69 | list_strategy.end(oss); 70 | } 71 | string str() const { return oss.str(); } 72 | private: 73 | ostringstream oss; 74 | LS list_strategy; 75 | }; 76 | 77 | int main() 78 | { 79 | // markdown 80 | TextProcessor tpm; 81 | tpm.append_list({"foo", "bar", "baz"}); 82 | cout << tpm.str() << endl; 83 | 84 | // html 85 | TextProcessor tph; 86 | tph.append_list({"foo", "bar", "baz"}); 87 | cout << tph.str() << endl; 88 | 89 | getchar(); 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /Creational/Creational/Serialization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "Person.h" 7 | using namespace std; 8 | #include 9 | #include 10 | #include 11 | 12 | struct Address 13 | { 14 | string street; 15 | string city; 16 | int suite; 17 | 18 | 19 | friend ostream& operator<<(ostream& os, const Address& obj) 20 | { 21 | return os 22 | << "street: " << obj.street 23 | << " city: " << obj.city 24 | << " suite: " << obj.suite; 25 | } 26 | 27 | private: 28 | friend class boost::serialization::access; 29 | 30 | template void serialize(Ar& ar, const unsigned int version) 31 | { 32 | ar & street; 33 | ar & city; 34 | ar & suite; 35 | } 36 | }; 37 | 38 | struct Contact 39 | { 40 | string name; 41 | Address* address = nullptr; 42 | 43 | friend ostream& operator<<(ostream& os, const Contact& obj) 44 | { 45 | return os 46 | << "name: " << obj.name 47 | << " address: " << *obj.address; 48 | } 49 | 50 | private: 51 | friend class boost::serialization::access; 52 | 53 | template void serialize(Ar& ar, const unsigned int version) 54 | { 55 | ar & name; 56 | ar & address; // no * 57 | } 58 | }; 59 | 60 | int main_() 61 | { 62 | Contact john; 63 | john.name = "John Doe"; 64 | john.address = new Address{ "123 East Dr", "London", 123 }; 65 | 66 | auto clone = [](const Contact& c) 67 | { 68 | ostringstream oss; 69 | boost::archive::text_oarchive oa(oss); 70 | oa << c; 71 | string s = oss.str(); 72 | 73 | istringstream iss(oss.str()); 74 | boost::archive::text_iarchive ia(iss); 75 | Contact result; 76 | ia >> result; 77 | return result; 78 | }; 79 | 80 | Contact jane = clone(john); 81 | jane.name = "Jane Doe"; 82 | jane.address->street = "123B West Dr"; 83 | jane.address->suite = 300; 84 | 85 | cout << john << endl << jane << endl; 86 | 87 | getchar(); 88 | return 0; 89 | } -------------------------------------------------------------------------------- /Structural/Composite/ArrayBackedProps.cpp: -------------------------------------------------------------------------------- 1 | #include "Headers.hpp" 2 | 3 | //class Creature 4 | //{ 5 | // int strength, agility, intelligence; 6 | // // new property 7 | // int charisma; 8 | //public: 9 | // int get_strength() const 10 | // { 11 | // return strength; 12 | // } 13 | // 14 | // void set_strength(int strength) 15 | // { 16 | // Creature::strength=strength; 17 | // } 18 | // 19 | // int get_agility() const 20 | // { 21 | // return agility; 22 | // } 23 | // 24 | // void set_agility(int agility) 25 | // { 26 | // Creature::agility=agility; 27 | // } 28 | // 29 | // int get_intelligence() const 30 | // { 31 | // return intelligence; 32 | // } 33 | // 34 | // void set_intelligence(int intelligence) 35 | // { 36 | // Creature::intelligence=intelligence; 37 | // } 38 | // 39 | // // sum, average, max. 40 | // 41 | // double sum() const { 42 | // return strength + agility + intelligence; 43 | // } 44 | // 45 | // double average() const { 46 | // return sum() / 3.0; 47 | // } 48 | // 49 | // int max() const { 50 | // return ::max(::max(strength, agility), intelligence); 51 | // } 52 | //}; 53 | 54 | class Creature 55 | { 56 | enum Abilities { str, agl, intl, count }; 57 | array abilities; 58 | public: 59 | int get_strength() const { return abilities[str]; } 60 | void set_strength(int value) { abilities[str] = value; } 61 | 62 | int get_agility() const { return abilities[agl]; } 63 | void set_agility(int value) { abilities[agl] = value; } 64 | 65 | int get_intelligence() const { return abilities[intl]; } 66 | void set_intelligence(int value) { abilities[intl] = value; } 67 | 68 | int sum() const { 69 | return accumulate(abilities.begin(), abilities.end(), 0); 70 | } 71 | 72 | double average() const { 73 | return sum() / (double)count; 74 | } 75 | 76 | int max() const { 77 | return *max_element(abilities.begin(), abilities.end()); 78 | } 79 | }; 80 | 81 | int main(int ac, char* av[]) 82 | { 83 | Creature orc; 84 | orc.set_strength(16); 85 | orc.set_agility(11); 86 | orc.set_intelligence(9); 87 | 88 | cout << "The orc has an average stat of " 89 | << orc.average() 90 | << " and a maximum stat of " 91 | << orc.max() 92 | << "\n"; 93 | 94 | return 0; 95 | } -------------------------------------------------------------------------------- /Creational/Creational/DIP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // A. High-level modules should not depend on low-level modules. 8 | // Both should depend on abstractions. 9 | // B. Abstractions should not depend on details. 10 | // Details should depend on abstractions. 11 | 12 | enum class Relationship 13 | { 14 | parent, 15 | child, 16 | sibling 17 | }; 18 | 19 | struct Person 20 | { 21 | string name; 22 | }; 23 | 24 | struct RelationshipBrowser 25 | { 26 | virtual vector find_all_children_of(const string& name) = 0; 27 | }; 28 | 29 | struct Relationships : RelationshipBrowser // low-level 30 | { 31 | vector> relations; 32 | 33 | void add_parent_and_child(const Person& parent, const Person& child) 34 | { 35 | relations.push_back({parent, Relationship::parent, child}); 36 | relations.push_back({child, Relationship::child, parent}); 37 | } 38 | 39 | vector find_all_children_of(const string &name) override 40 | { 41 | vector result; 42 | for (auto&& [first, rel, second] : relations) 43 | { 44 | if (first.name == name && rel == Relationship::parent) 45 | { 46 | result.push_back(second); 47 | } 48 | } 49 | return result; 50 | } 51 | }; 52 | 53 | struct Research // high-level 54 | { 55 | Research(RelationshipBrowser& browser) 56 | { 57 | for (auto& child : browser.find_all_children_of("John")) 58 | { 59 | cout << "John has a child called " << child.name << endl; 60 | } 61 | } 62 | // Research(const Relationships& relationships) 63 | // { 64 | // auto& relations = relationships.relations; 65 | // for (auto&& [first, rel, second] : relations) 66 | // { 67 | // if (first.name == "John" && rel == Relationship::parent) 68 | // { 69 | // cout << "John has a child called " << second.name << endl; 70 | // } 71 | // } 72 | // } 73 | }; 74 | 75 | int main() 76 | { 77 | Person parent{"John"}; 78 | Person child1{"Chris"}; 79 | Person child2{"Matt"}; 80 | 81 | Relationships relationships; 82 | relationships.add_parent_and_child(parent, child1); 83 | relationships.add_parent_and_child(parent, child2); 84 | 85 | Research _(relationships); 86 | 87 | return 0; 88 | } -------------------------------------------------------------------------------- /Structural/Flyweight/capitalize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class FormattedText 8 | { 9 | string plain_text; 10 | bool *caps; 11 | public: 12 | explicit FormattedText(const string& plainText) 13 | : plain_text{plainText} 14 | { 15 | caps = new bool[plainText.length()]; 16 | memset(caps, 0, plain_text.length()); 17 | } 18 | ~FormattedText() 19 | { 20 | delete[] caps; 21 | } 22 | void capitalize(int start, int end) 23 | { 24 | for (int i = start; i <= end; ++i) 25 | caps[i] = true; 26 | } 27 | 28 | friend std::ostream& operator<<(std::ostream& os, const FormattedText& obj) 29 | { 30 | string s; 31 | for (int i = 0; i < obj.plain_text.length(); ++i) 32 | { 33 | char c = obj.plain_text[i]; 34 | s += (obj.caps[i] ? toupper(c) : c); 35 | } 36 | return os << s; 37 | } 38 | }; 39 | 40 | class BetterFormattedText 41 | { 42 | public: 43 | struct TextRange 44 | { 45 | int start, end; 46 | bool capitalize, bold, italic; 47 | 48 | bool covers(int position) const 49 | { 50 | return position >= start && position <= end; 51 | } 52 | }; 53 | 54 | TextRange& get_range(int start, int end) 55 | { 56 | formatting.emplace_back(TextRange{ start, end }); 57 | return *formatting.rbegin(); 58 | } 59 | 60 | explicit BetterFormattedText(const string& plainText) 61 | : plain_text{plainText} 62 | { 63 | } 64 | 65 | friend std::ostream& operator<<(std::ostream& os, const BetterFormattedText& obj) 66 | { 67 | string s; 68 | for (size_t i = 0; i < obj.plain_text.length(); i++) 69 | { 70 | auto c = obj.plain_text[i]; 71 | for (const auto& rng : obj.formatting) 72 | { 73 | if (rng.covers(i) && rng.capitalize) 74 | c = toupper(c); 75 | } 76 | s += c; // fixed! 77 | } 78 | return os << s; 79 | } 80 | 81 | private: 82 | string plain_text; 83 | vector formatting; 84 | }; 85 | 86 | int main(int argc, char* argv[]) 87 | { 88 | FormattedText ft("This is a brave new world"); 89 | ft.capitalize(10, 15); 90 | cout << ft << endl; 91 | 92 | BetterFormattedText bft("This is a brave new world"); 93 | bft.get_range(10, 15).capitalize = true; 94 | cout << bft << endl; 95 | } 96 | -------------------------------------------------------------------------------- /Structural/PingPongService/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNet.Builder; 6 | using Microsoft.AspNet.Hosting; 7 | using Microsoft.Extensions.Configuration; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace PingPongService 12 | { 13 | public class Startup 14 | { 15 | public Startup(IHostingEnvironment env) 16 | { 17 | // Set up configuration sources. 18 | var builder = new ConfigurationBuilder() 19 | .AddJsonFile("appsettings.json"); 20 | 21 | if (env.IsEnvironment("Development")) 22 | { 23 | // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately. 24 | builder.AddApplicationInsightsSettings(developerMode: true); 25 | } 26 | 27 | builder.AddEnvironmentVariables(); 28 | Configuration = builder.Build().ReloadOnChanged("appsettings.json"); 29 | } 30 | 31 | public IConfigurationRoot Configuration { get; set; } 32 | 33 | // This method gets called by the runtime. Use this method to add services to the container 34 | public void ConfigureServices(IServiceCollection services) 35 | { 36 | // Add framework services. 37 | services.AddApplicationInsightsTelemetry(Configuration); 38 | 39 | services.AddMvc(); 40 | } 41 | 42 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline 43 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 44 | { 45 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 46 | loggerFactory.AddDebug(); 47 | 48 | app.UseIISPlatformHandler(); 49 | 50 | app.UseApplicationInsightsRequestTelemetry(); 51 | 52 | app.UseApplicationInsightsExceptionTelemetry(); 53 | 54 | app.UseStaticFiles(); 55 | 56 | app.UseMvc(); 57 | } 58 | 59 | // Entry point for the application. 60 | public static void Main(string[] args) => WebApplication.Run(args); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Structural/AdapterVisual/AdapterVisual.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | 49 | 50 | Resource Files 51 | 52 | 53 | 54 | 55 | Resource Files 56 | 57 | 58 | 59 | 60 | Resource Files 61 | 62 | 63 | -------------------------------------------------------------------------------- /Behavioral/Visitor/multimethods.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct GameObject; 9 | void collide(GameObject& first, GameObject& second); 10 | 11 | struct GameObject 12 | { 13 | virtual ~GameObject() = default; 14 | virtual type_index type() const = 0; 15 | 16 | virtual void collide(GameObject& other) { ::collide(*this, other); } 17 | }; 18 | 19 | template struct GameObjectImpl : GameObject 20 | { 21 | type_index type() const override 22 | { 23 | return typeid(T); 24 | } 25 | }; 26 | 27 | struct Planet : GameObjectImpl {}; 28 | struct Asteroid : GameObjectImpl {}; 29 | struct Spaceship : GameObjectImpl {}; 30 | struct ArmedSpaceship : Spaceship 31 | { 32 | type_index type() const override { 33 | return typeid(ArmedSpaceship); // required for collision to function 34 | } 35 | }; // model limitation 36 | 37 | void spaceship_planet() { cout << "spaceship lands on planet\n"; } 38 | void asteroid_planet() { cout << "asteroid burns up in atmosphere\n"; } 39 | void asteroid_spaceship() { cout << "asteroid hits and destroys spaceship\n"; } 40 | void asteroid_armed_spaceship() { cout << "spaceship shoots asteroid\n"; } 41 | 42 | map, void(*)(void)> outcomes{ 43 | {{typeid(Spaceship), typeid(Planet)}, spaceship_planet}, 44 | {{typeid(Asteroid),typeid(Planet)}, asteroid_planet}, 45 | {{typeid(Asteroid),typeid(Spaceship)}, asteroid_spaceship}, 46 | {{typeid(Asteroid), typeid(ArmedSpaceship)}, asteroid_armed_spaceship} 47 | }; 48 | 49 | void collide(GameObject& first, GameObject& second) 50 | { 51 | auto it = outcomes.find({ first.type(), second.type() }); 52 | if (it == outcomes.end()) 53 | { 54 | it = outcomes.find({ second.type(), first.type() }); 55 | if (it == outcomes.end()) 56 | { 57 | cout << "objects pass each other harmlessly\n"; 58 | return; 59 | } 60 | } 61 | it->second(); 62 | } 63 | 64 | int main__(int argc, char* argv[]) 65 | { 66 | ArmedSpaceship spaceship; 67 | Asteroid asteroid; 68 | Planet planet; 69 | 70 | collide(planet, spaceship); 71 | collide(planet, asteroid); 72 | collide(spaceship, asteroid); 73 | collide(planet, planet); 74 | 75 | cout << "Member collision:\n"; 76 | planet.collide(asteroid); 77 | 78 | // but this won't work 79 | spaceship.collide(planet); 80 | 81 | getchar(); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /Behavioral/Observer/observer1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | #include 6 | using namespace boost; 7 | 8 | namespace 9 | { 10 | 11 | struct Person; 12 | 13 | struct PersonListener 14 | { 15 | virtual ~PersonListener() = default; 16 | virtual void person_changed(Person& p, const string& property_name, const any new_value) = 0; 17 | }; 18 | 19 | struct Person 20 | { 21 | explicit Person(int age) 22 | : age(age) 23 | { 24 | } 25 | 26 | int get_age() const 27 | { 28 | return age; 29 | } 30 | 31 | void set_age(const int age); 32 | 33 | bool get_can_vote() const 34 | { 35 | return age >= 16; 36 | } 37 | 38 | void subscribe(PersonListener* pl); 39 | 40 | void notify(const string& property_name, const any new_value); 41 | private: 42 | int age; 43 | vector listeners; 44 | }; 45 | 46 | void Person::set_age(const int age) 47 | { 48 | if (this->age == age) return; 49 | 50 | auto old_c_v = get_can_vote(); 51 | 52 | this->age = age; 53 | notify("age", this->age); 54 | 55 | auto new_c_v = get_can_vote(); 56 | if (old_c_v != new_c_v) 57 | { 58 | notify("can_vote", new_c_v); 59 | } 60 | } 61 | 62 | void Person::subscribe(PersonListener* pl) 63 | { 64 | listeners.push_back(pl); 65 | } 66 | 67 | void Person::notify(const string& property_name, const any new_value) 68 | { 69 | for (const auto listener : listeners) 70 | listener->person_changed(*this, property_name, new_value); 71 | } 72 | 73 | struct ConsoleListener : PersonListener 74 | { 75 | void person_changed(Person& p, const string& property_name, const any new_value) override 76 | { 77 | cout << "person's " << property_name << " has been changed to "; 78 | if (property_name == "age") 79 | { 80 | cout << any_cast(new_value); 81 | } 82 | else if (property_name == "can_vote") 83 | { 84 | cout << any_cast(new_value); 85 | } 86 | cout << "\n"; 87 | } 88 | }; 89 | 90 | int main() 91 | { 92 | Person p{ 14 }; 93 | ConsoleListener cl; 94 | p.subscribe(&cl); 95 | p.set_age(15); 96 | p.set_age(16); 97 | 98 | 99 | getchar(); 100 | return 0; 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /Behavioral/Command/command_undo.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.hpp" 2 | 3 | struct BankAccount 4 | { 5 | int balance{0}; 6 | int overdraft_limit{-500}; 7 | 8 | void deposit(int amount) 9 | { 10 | balance += amount; 11 | cout << "deposited " << amount 12 | << ", balance is now " << balance << endl; 13 | } 14 | 15 | bool withdraw(int amount) 16 | { 17 | if (balance - amount >= overdraft_limit) 18 | { 19 | balance -= amount; 20 | cout << "withdrew " << amount 21 | << ", balance is now " << balance << endl; 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | friend ostream &operator<<(ostream &os, const BankAccount &account) { 28 | os << "balance: " << account.balance; 29 | return os; 30 | } 31 | }; 32 | 33 | struct Command 34 | { 35 | bool succeeded; 36 | virtual void call() = 0; 37 | virtual void undo() = 0; 38 | }; 39 | 40 | struct BankAccountCommand : Command 41 | { 42 | BankAccount& account; 43 | enum Action { deposit, withdraw } action; 44 | int amount; 45 | 46 | BankAccountCommand(BankAccount &account, Action action, int amount) : account(account), action(action), 47 | amount(amount) { 48 | succeeded = false; 49 | } 50 | 51 | void call() override { 52 | switch (action) 53 | { 54 | case deposit: 55 | account.deposit(amount); 56 | succeeded = true; 57 | break; 58 | case withdraw: 59 | succeeded = account.withdraw(amount); 60 | break; 61 | } 62 | } 63 | 64 | void undo() override { 65 | if (!succeeded) return; 66 | 67 | switch (action) 68 | { 69 | case deposit: 70 | account.withdraw(amount); 71 | break; 72 | case withdraw: 73 | account.deposit(amount); 74 | break; 75 | } 76 | } 77 | 78 | 79 | }; 80 | 81 | int main() 82 | { 83 | BankAccount ba; 84 | 85 | vector commands 86 | { 87 | BankAccountCommand{ba, BankAccountCommand::deposit, 100}, 88 | BankAccountCommand{ba, BankAccountCommand::withdraw, 200} 89 | }; 90 | 91 | cout << ba << endl; 92 | 93 | for (auto& cmd : commands) 94 | cmd.call(); 95 | 96 | for (auto it = commands.rbegin(); it != commands.rend(); ++it) 97 | { 98 | it->undo(); 99 | } 100 | 101 | cout << ba << endl; 102 | 103 | return 0; 104 | } -------------------------------------------------------------------------------- /Behavioral/Strategy/strategy_dynamic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | enum class OutputFormat 9 | { 10 | Markdown, 11 | Html 12 | }; 13 | 14 | struct ListStrategy 15 | { 16 | virtual ~ListStrategy() = default; 17 | virtual void add_list_item(ostringstream& oss, const string& item) {}; 18 | virtual void start(ostringstream& oss) {}; 19 | virtual void end(ostringstream& oss) {}; 20 | }; 21 | 22 | struct MarkdownListStrategy : ListStrategy 23 | { 24 | void add_list_item(ostringstream& oss, const string& item) override 25 | { 26 | oss << " * " << item << endl; 27 | } 28 | }; 29 | 30 | struct HtmlListStrategy : ListStrategy 31 | { 32 | void start(ostringstream& oss) override 33 | { 34 | oss << "
      " << endl; 35 | } 36 | 37 | void end(ostringstream& oss) override 38 | { 39 | oss << "
    " << endl; 40 | } 41 | 42 | void add_list_item(ostringstream& oss, const string& item) override 43 | { 44 | oss << "
  • " << item << "
  • " << endl; 45 | } 46 | }; 47 | 48 | struct TextProcessor 49 | { 50 | void clear() 51 | { 52 | oss.str(""); 53 | oss.clear(); 54 | } 55 | void append_list(const vector items) 56 | { 57 | list_strategy->start(oss); 58 | for (auto& item : items) 59 | list_strategy->add_list_item(oss, item); 60 | list_strategy->end(oss); 61 | } 62 | 63 | void set_output_format(const OutputFormat format) 64 | { 65 | switch(format) 66 | { 67 | case OutputFormat::Markdown: 68 | list_strategy = make_unique(); 69 | break; 70 | case OutputFormat::Html: 71 | list_strategy = make_unique(); 72 | break; 73 | default: 74 | throw runtime_error("Unsupported strategy."); 75 | } 76 | } 77 | string str() const { return oss.str(); } 78 | private: 79 | ostringstream oss; 80 | unique_ptr list_strategy; 81 | }; 82 | 83 | int main_() 84 | { 85 | // markdown 86 | TextProcessor tp; 87 | tp.set_output_format(OutputFormat::Markdown); 88 | tp.append_list({"foo", "bar", "baz"}); 89 | cout << tp.str() << endl; 90 | 91 | // html 92 | tp.clear(); 93 | tp.set_output_format(OutputFormat::Html); 94 | tp.append_list({"foo", "bar", "baz"}); 95 | cout << tp.str() << endl; 96 | 97 | getchar(); 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /Behavioral/Visitor/model.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct Visitor; 5 | 6 | struct Element 7 | { 8 | virtual ~Element() = default; 9 | 10 | // print 11 | virtual void print_html(ostringstream& oss) const = 0; 12 | // violates open-closed 13 | // virtual void print_markdown(ostringstream& oss) const = 0; 14 | 15 | // visitor 16 | virtual void accept(Visitor& v) const = 0; 17 | }; 18 | 19 | struct Div : vector, Element 20 | { 21 | Div(const initializer_list& _Ilist) 22 | : vector(_Ilist) 23 | { 24 | } 25 | 26 | 27 | void accept(Visitor& v) const override 28 | { 29 | } 30 | 31 | void print_html(ostringstream& oss) const override 32 | { 33 | oss << "
    \n"; 34 | for_each(begin(), end(), [&](const Element* e) 35 | { 36 | e->print_html(oss); 37 | }); 38 | oss << "
    \n"; 39 | } 40 | }; 41 | 42 | struct TextElement : Element 43 | { 44 | explicit TextElement(const string& text) 45 | : text(text) 46 | { 47 | } 48 | 49 | string text; 50 | }; 51 | 52 | struct Paragraph : TextElement 53 | { 54 | explicit Paragraph(const string& text) 55 | : TextElement(text) 56 | { 57 | } 58 | 59 | 60 | void accept(Visitor& v) const override 61 | { 62 | v.visit(*this); 63 | } 64 | 65 | void print_html(ostringstream& oss) const override 66 | { 67 | oss << "

    " << text << "

    \n"; 68 | } 69 | }; 70 | 71 | struct BoldParagraph : Paragraph 72 | { 73 | explicit BoldParagraph(const string& text) 74 | : Paragraph(text) 75 | { 76 | } 77 | 78 | 79 | void accept(Visitor& v) const override { 80 | v.visit(*this); 81 | } 82 | }; 83 | 84 | struct ListItem : TextElement 85 | { 86 | explicit ListItem(const string& text) 87 | : TextElement(text) 88 | { 89 | } 90 | 91 | void accept(Visitor& v) const override 92 | { 93 | v.visit(*this); 94 | } 95 | 96 | void print_html(ostringstream& oss) const override 97 | { 98 | oss << "
  • " << text << "
  • \n"; 99 | } 100 | }; 101 | 102 | struct List : Element, vector 103 | { 104 | List(const initializer_list& list) 105 | : vector(list) 106 | { 107 | } 108 | 109 | 110 | void accept(Visitor& v) const override 111 | { 112 | v.visit(*this); 113 | } 114 | 115 | void print_html(ostringstream& oss) const override 116 | { 117 | oss << "
      \n"; 118 | for_each(begin(), end(), [&](const ListItem& li) { li.print_html(oss); }); 119 | oss << "
    \n"; 120 | } 121 | }; -------------------------------------------------------------------------------- /Structural/Composite/neurons.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | struct Neuron; 11 | 12 | template 13 | struct SomeNeurons 14 | { 15 | template void connect_to(T& other) 16 | { 17 | for (Neuron& from : *static_cast(this)) 18 | { 19 | for (Neuron& to : other) 20 | { 21 | from.out.push_back(&to); 22 | to.in.push_back(&from); 23 | } 24 | } 25 | } 26 | }; 27 | 28 | struct Neuron : SomeNeurons 29 | { 30 | vector in, out; 31 | unsigned int id; 32 | 33 | Neuron() 34 | { 35 | static int id = 1; 36 | this->id = id++; 37 | } 38 | 39 | /*template void connect_to(T& other) 40 | { 41 | for (Neuron& target : other) 42 | connect_to(target); 43 | }*/ 44 | 45 | // legal in MSVC only 46 | /*template<> void connect_to(Neuron& other) 47 | { 48 | out.push_back(&other); 49 | other.in.push_back(this); 50 | }*/ 51 | 52 | // connect_to(vector&) 53 | 54 | Neuron* begin() { return this; } 55 | Neuron* end() { return this + 1; } 56 | 57 | friend ostream& operator<<(ostream& os, const Neuron& obj) 58 | { 59 | for (Neuron* n : obj.in) 60 | { 61 | os << n->id << "\t-->\t[" << obj.id << "]" << endl; 62 | } 63 | 64 | for (Neuron* n : obj.out) 65 | { 66 | os << "[" << obj.id << "]\t-->\t" << n->id << endl; 67 | } 68 | return os; 69 | } 70 | }; 71 | 72 | struct NeuronLayer : vector, SomeNeurons 73 | { 74 | NeuronLayer(int count) 75 | { 76 | while (count-- > 0) 77 | emplace_back(Neuron{}); 78 | } 79 | 80 | friend ostream& operator<<(ostream& os, NeuronLayer& obj) 81 | { 82 | 83 | for (auto& n : obj) os << n; 84 | return os; 85 | } 86 | }; 87 | 88 | void main() 89 | { 90 | Neuron n1, n2; 91 | n1.connect_to(n2); 92 | 93 | cout << n1 << n2 << endl; 94 | 95 | NeuronLayer l1{5}; 96 | Neuron n3; 97 | l1.connect_to(n3); 98 | 99 | cout << "Neuron " << n3.id << endl << n3 << endl; 100 | cout << "Layer " << endl << l1 << endl; 101 | 102 | NeuronLayer l2{ 2 }, l3{ 3 }; 103 | l2.connect_to(l3); 104 | cout << "Layer l2" << endl << l2; 105 | cout << "Layer l3" << endl << l3; 106 | } -------------------------------------------------------------------------------- /Creational/Creational/Singleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Database 10 | { 11 | public: 12 | virtual int get_population(const std::string& name) = 0; 13 | }; 14 | 15 | class SingletonDatabase : public Database 16 | { 17 | SingletonDatabase() 18 | { 19 | std::cout << "Initializing database" << std::endl; 20 | 21 | std::ifstream ifs("capitals.txt"); 22 | 23 | std::string s, s2; 24 | while (getline(ifs, s)) 25 | { 26 | getline(ifs, s2); 27 | int pop = boost::lexical_cast(s2); 28 | capitals[s] = pop; 29 | } 30 | //instance_count++; 31 | } 32 | 33 | std::map capitals; 34 | 35 | public: 36 | //static int instance_count; 37 | 38 | SingletonDatabase(SingletonDatabase const&) = delete; 39 | void operator=(SingletonDatabase const&) = delete; 40 | 41 | static SingletonDatabase& get() 42 | { 43 | static SingletonDatabase db; 44 | return db; 45 | } 46 | 47 | int get_population(const std::string& name) override 48 | { 49 | return capitals[name]; 50 | } 51 | 52 | /* 53 | static SingletonDatabase* get_instance() 54 | { 55 | if (!instance) 56 | instance = new SingletonDatabase; 57 | return instance; // atexit 58 | } 59 | */ 60 | }; 61 | 62 | //int SingletonDatabase::instance_count = 0; 63 | 64 | class DummyDatabase : public Database 65 | { 66 | std::map capitals; 67 | public: 68 | 69 | 70 | DummyDatabase() 71 | { 72 | capitals["alpha"] = 1; 73 | capitals["beta"] = 2; 74 | capitals["gamma"] = 3; 75 | } 76 | 77 | int get_population(const std::string& name) override { 78 | return capitals[name]; 79 | } 80 | }; 81 | 82 | struct SingletonRecordFinder 83 | { 84 | int total_population(std::vector names) 85 | { 86 | int result = 0; 87 | for (auto& name : names) 88 | result += SingletonDatabase::get().get_population(name); 89 | return result; 90 | } 91 | }; 92 | 93 | struct ConfigurableRecordFinder 94 | { 95 | explicit ConfigurableRecordFinder(Database& db) 96 | : db{db} 97 | { 98 | } 99 | 100 | int total_population(std::vector names) const 101 | { 102 | int result = 0; 103 | for (auto& name : names) 104 | result += db.get_population(name); 105 | return result; 106 | } 107 | 108 | Database& db; 109 | }; -------------------------------------------------------------------------------- /Creational/Creational/Builder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct HtmlBuilder; 9 | 10 | struct HtmlElement 11 | { 12 | string name; 13 | string text; 14 | vector elements; 15 | const size_t indent_size = 2; 16 | 17 | HtmlElement() {} 18 | HtmlElement(const string& name, const string& text) 19 | : name(name), 20 | text(text) 21 | { 22 | } 23 | 24 | string str(int indent = 0) const 25 | { 26 | ostringstream oss; 27 | string i(indent_size*indent, ' '); 28 | oss << i << "<" << name << ">" << endl; 29 | if (text.size() > 0) 30 | oss << string(indent_size*(indent + 1), ' ') << text << endl; 31 | 32 | for (const auto& e : elements) 33 | oss << e.str(indent + 1); 34 | 35 | oss << i << "" << endl; 36 | return oss.str(); 37 | } 38 | 39 | static unique_ptr build(string root_name) 40 | { 41 | return make_unique(root_name); 42 | } 43 | }; 44 | 45 | struct HtmlBuilder 46 | { 47 | HtmlBuilder(string root_name) 48 | { 49 | root.name = root_name; 50 | } 51 | 52 | // void to start with 53 | HtmlBuilder& add_child(string child_name, string child_text) 54 | { 55 | HtmlElement e{ child_name, child_text }; 56 | root.elements.emplace_back(e); 57 | return *this; 58 | } 59 | 60 | // pointer based 61 | HtmlBuilder* add_child_2(string child_name, string child_text) 62 | { 63 | HtmlElement e{ child_name, child_text }; 64 | root.elements.emplace_back(e); 65 | return this; 66 | } 67 | 68 | string str() { return root.str(); } 69 | 70 | operator HtmlElement() const { return root; } 71 | HtmlElement root; 72 | }; 73 | 74 | int demo() 75 | { 76 | //

    hello

    77 | auto text = "hello"; 78 | string output; 79 | output += "

    "; 80 | output += text; 81 | output += "

    "; 82 | printf("

    %s

    ", text); 83 | 84 | //
    • hello
    • world
    85 | string words[] = { "hello", "world" }; 86 | ostringstream oss; 87 | oss << "
      "; 88 | for (auto w : words) 89 | oss << "
    • " << w << "
    • "; 90 | oss << "
    "; 91 | printf(oss.str().c_str()); 92 | 93 | // easier 94 | HtmlBuilder builder{ "ul" }; 95 | builder.add_child("li", "hello").add_child("li", "world"); 96 | cout << builder.str() << endl; 97 | 98 | 99 | auto builder2 = HtmlElement::build("ul") 100 | ->add_child_2("li", "hello")->add_child_2("li", "world"); 101 | cout << builder2 << endl; 102 | 103 | getchar(); 104 | return 0; 105 | } -------------------------------------------------------------------------------- /Structural/AdapterVisual/AdapterVisual.cpp: -------------------------------------------------------------------------------- 1 | 2 | // AdapterVisual.cpp : Defines the class behaviors for the application. 3 | // 4 | 5 | #include "stdafx.h" 6 | #include "AdapterVisual.h" 7 | #include "AdapterVisualDlg.h" 8 | 9 | #ifdef _DEBUG 10 | #define new DEBUG_NEW 11 | #endif 12 | 13 | 14 | // CAdapterVisualApp 15 | 16 | BEGIN_MESSAGE_MAP(CAdapterVisualApp, CWinApp) 17 | ON_COMMAND(ID_HELP, &CWinApp::OnHelp) 18 | END_MESSAGE_MAP() 19 | 20 | 21 | // CAdapterVisualApp construction 22 | 23 | CAdapterVisualApp::CAdapterVisualApp() 24 | { 25 | // support Restart Manager 26 | m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; 27 | 28 | // TODO: add construction code here, 29 | // Place all significant initialization in InitInstance 30 | } 31 | 32 | 33 | // The one and only CAdapterVisualApp object 34 | 35 | CAdapterVisualApp theApp; 36 | 37 | 38 | // CAdapterVisualApp initialization 39 | 40 | BOOL CAdapterVisualApp::InitInstance() 41 | { 42 | // InitCommonControlsEx() is required on Windows XP if an application 43 | // manifest specifies use of ComCtl32.dll version 6 or later to enable 44 | // visual styles. Otherwise, any window creation will fail. 45 | INITCOMMONCONTROLSEX InitCtrls; 46 | InitCtrls.dwSize = sizeof(InitCtrls); 47 | // Set this to include all the common control classes you want to use 48 | // in your application. 49 | InitCtrls.dwICC = ICC_WIN95_CLASSES; 50 | InitCommonControlsEx(&InitCtrls); 51 | 52 | CWinApp::InitInstance(); 53 | 54 | 55 | AfxEnableControlContainer(); 56 | 57 | 58 | // Standard initialization 59 | // If you are not using these features and wish to reduce the size 60 | // of your final executable, you should remove from the following 61 | // the specific initialization routines you do not need 62 | // Change the registry key under which our settings are stored 63 | // TODO: You should modify this string to be something appropriate 64 | // such as the name of your company or organization 65 | SetRegistryKey(_T("Local AppWizard-Generated Applications")); 66 | 67 | CAdapterVisualDlg dlg; 68 | m_pMainWnd = &dlg; 69 | INT_PTR nResponse = dlg.DoModal(); 70 | if (nResponse == IDOK) 71 | { 72 | // TODO: Place code here to handle when the dialog is 73 | // dismissed with OK 74 | } 75 | else if (nResponse == IDCANCEL) 76 | { 77 | // TODO: Place code here to handle when the dialog is 78 | // dismissed with Cancel 79 | } 80 | else if (nResponse == -1) 81 | { 82 | TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n"); 83 | } 84 | 85 | 86 | // Since the dialog has been closed, return FALSE so that we exit the 87 | // application, rather than start the application's message pump. 88 | return FALSE; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /Behavioral/Interpreter/InterpreterCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | inline vector split(const string& stringToSplit) 10 | { 11 | vector result; 12 | size_t pos = 0, lastPos = 0; 13 | while ((pos = stringToSplit.find_first_of("+-", lastPos)) != string::npos) 14 | { 15 | result.push_back(stringToSplit.substr(lastPos, pos-lastPos+1)); 16 | lastPos = pos+1; 17 | } 18 | result.push_back(stringToSplit.substr(lastPos)); 19 | return result; 20 | } 21 | 22 | struct ExpressionProcessor 23 | { 24 | map variables; 25 | 26 | enum NextOp 27 | { 28 | nothing, 29 | plus, 30 | minus 31 | }; 32 | 33 | int calculate(const string& expression) 34 | { 35 | int current; 36 | auto next_op = nothing; 37 | 38 | auto parts = split(expression); 39 | 40 | cout << "parts (" << parts.size() << "): "; 41 | for (auto& part : parts) 42 | cout << "`" << part << "` "; 43 | cout << endl; 44 | 45 | for (auto& part : parts) 46 | { 47 | auto no_op = split(part); 48 | auto first = no_op[0]; 49 | int value, z; 50 | 51 | try 52 | { 53 | value = stoi(first); 54 | } 55 | catch (const invalid_argument&) 56 | { 57 | if (first.length() == 1 && 58 | variables.find(first[0]) != variables.end()) 59 | { 60 | value = variables[first[0]]; 61 | } 62 | else return 0; 63 | } 64 | 65 | switch (next_op) 66 | { 67 | case nothing: 68 | current = value; 69 | break; 70 | case plus: 71 | current += value; 72 | break; 73 | case minus: 74 | current -= value; 75 | break; 76 | } 77 | 78 | if (*part.rbegin() == '+') next_op = plus; 79 | else if (*part.rbegin() == '-') next_op = minus; 80 | } 81 | 82 | return current; 83 | } 84 | }; 85 | 86 | #include "gtest/gtest.h" 87 | 88 | //#include "helpers/iohelper.h" 89 | 90 | //#include "exercise.cpp" 91 | 92 | namespace 93 | { 94 | class Evaluate : public testing::Test 95 | { 96 | public: 97 | }; 98 | 99 | TEST_F(Evaluate, LotsOfAccountTests) 100 | { 101 | ExpressionProcessor ep; 102 | ep.variables['x'] = 5; 103 | 104 | ASSERT_EQ(1, ep.calculate("1")); 105 | ASSERT_EQ(3, ep.calculate("1+2")); 106 | ASSERT_EQ(6, ep.calculate("1+x")); 107 | ASSERT_EQ(0, ep.calculate("1+xy")); 108 | } 109 | } // namespace 110 | 111 | int main(int ac, char* av[]) 112 | { 113 | testing::InitGoogleTest(&ac, av); 114 | return RUN_ALL_TESTS(); 115 | } -------------------------------------------------------------------------------- /Behavioral/Observer/ObserverCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct IRat 6 | { 7 | virtual void rat_enters(IRat* sender) = 0; 8 | virtual void rat_dies(IRat* sender) = 0; 9 | virtual void notify(IRat* target) = 0; 10 | }; 11 | 12 | struct Game 13 | { 14 | vector rats; 15 | virtual void fire_rat_enters(IRat* sender) 16 | { 17 | for (auto rat : rats) rat->rat_enters(sender); 18 | } 19 | virtual void fire_rat_dies(IRat* sender) 20 | { 21 | for (auto rat : rats) rat->rat_dies(sender); 22 | } 23 | virtual void fire_notify(IRat* target) 24 | { 25 | for (auto rat : rats) rat->notify(target); 26 | } 27 | }; 28 | 29 | struct Rat : IRat 30 | { 31 | Game& game; 32 | int attack{1}; 33 | 34 | Rat(Game &game) : game(game) 35 | { 36 | game.rats.push_back(this); 37 | game.fire_rat_enters(this); 38 | } 39 | 40 | ~Rat() { game.fire_rat_dies(this); } 41 | 42 | void rat_enters(IRat *sender) override { 43 | if (sender != this) 44 | { 45 | ++attack; 46 | game.fire_notify(sender); 47 | } 48 | } 49 | 50 | void rat_dies(IRat *sender) override { 51 | --attack; 52 | } 53 | 54 | void notify(IRat *target) override { 55 | if (target == this) ++attack; 56 | } 57 | }; 58 | 59 | #include "gtest/gtest.h" 60 | 61 | //#include "helpers/iohelper.h" 62 | 63 | //#include "exercise.cpp" 64 | 65 | namespace { 66 | 67 | class Evaluate : public ::testing::Test {}; 68 | 69 | TEST_F(Evaluate, SingleRatTest) 70 | { 71 | Game game; 72 | Rat rat{game}; 73 | ASSERT_EQ(1, rat.attack); 74 | } 75 | 76 | TEST_F(Evaluate, TwoRatTest) 77 | { 78 | Game game; 79 | Rat rat{game}; 80 | Rat rat2{game}; 81 | ASSERT_EQ(2, rat.attack); 82 | ASSERT_EQ(2, rat2.attack); 83 | } 84 | 85 | TEST_F(Evaluate, ThreeRatsOneDies) 86 | { 87 | Game game; 88 | Rat rat{game}; 89 | ASSERT_EQ(1, rat.attack); 90 | 91 | Rat rat2{game}; 92 | ASSERT_EQ(2, rat.attack); 93 | ASSERT_EQ(2, rat2.attack); 94 | 95 | { 96 | Rat rat3{game}; 97 | 98 | ASSERT_EQ(3, rat.attack); 99 | ASSERT_EQ(3, rat2.attack); 100 | ASSERT_EQ(3, rat3.attack); 101 | } 102 | 103 | ASSERT_EQ(2, rat.attack); 104 | ASSERT_EQ(2, rat2.attack); 105 | } 106 | 107 | } // namespace 108 | 109 | // ERROR ON UDEMY'S END, POST AGAIN 110 | 111 | int main(int ac, char* av[]) 112 | { 113 | //::testing::GTEST_FLAG(catch_exceptions) = false; 114 | testing::InitGoogleTest(&ac, av); 115 | return RUN_ALL_TESTS(); 116 | } -------------------------------------------------------------------------------- /Behavioral/ChainOfResponsibility/cor_broker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | #include 5 | using namespace boost::signals2; 6 | 7 | 8 | struct Query 9 | { 10 | string creature_name; 11 | enum Argument { attack, defense } argument; 12 | int result; 13 | 14 | 15 | Query(const string& creature_name, const Argument argument, const int result) 16 | : creature_name(creature_name), 17 | argument(argument), 18 | result(result) 19 | { 20 | } 21 | }; 22 | 23 | struct Game // mediator 24 | { 25 | signal queries; 26 | }; 27 | 28 | class Creature 29 | { 30 | Game& game; 31 | int attack, defense; 32 | public: 33 | string name; 34 | Creature(Game& game, const string& name, const int attack, const int defense) 35 | : game(game), 36 | attack(attack), 37 | defense(defense), 38 | name(name) 39 | { 40 | } 41 | 42 | // no need for this to be virtual 43 | int GetAttack() const 44 | { 45 | Query q{ name, Query::Argument::attack, attack }; 46 | game.queries(q); 47 | return q.result; 48 | } 49 | 50 | friend ostream& operator<<(ostream& os, const Creature& obj) 51 | { 52 | return os 53 | << "name: " << obj.name 54 | << " attack: " << obj.GetAttack() // note here 55 | << " defense: " << obj.defense; 56 | } 57 | }; 58 | 59 | class CreatureModifier 60 | { 61 | Game& game; 62 | Creature& creature; 63 | public: 64 | virtual ~CreatureModifier() = default; 65 | 66 | // there is no handle() function 67 | 68 | CreatureModifier(Game& game, Creature& creature) 69 | : game(game), 70 | creature(creature) 71 | { 72 | } 73 | }; 74 | 75 | class DoubleAttackModifier : public CreatureModifier 76 | { 77 | connection conn; 78 | public: 79 | DoubleAttackModifier(Game& game, Creature& creature) 80 | : CreatureModifier(game, creature) 81 | { 82 | // whenever someone wants this creature's attack, 83 | // we return DOUBLE the value 84 | conn = game.queries.connect([&](Query& q) 85 | { 86 | if (q.creature_name == creature.name && 87 | q.argument == Query::Argument::attack) 88 | q.result *= 2; 89 | }); 90 | } 91 | 92 | ~DoubleAttackModifier() 93 | { 94 | conn.disconnect(); 95 | } 96 | }; 97 | 98 | // similar idea, but Query instead of Command 99 | int main(int ac, char* av) 100 | { 101 | Game game; 102 | Creature goblin{ game, "Strong Goblin", 2, 2 }; 103 | 104 | cout << goblin << endl; 105 | 106 | { 107 | DoubleAttackModifier dam{ game, goblin }; 108 | 109 | cout << goblin << endl; 110 | } 111 | 112 | cout << goblin << endl; 113 | 114 | getchar(); 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /Behavioral/Memento/MementoCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct Token 7 | { 8 | int value; 9 | 10 | Token(int value) : value(value) {} 11 | }; 12 | 13 | struct Memento 14 | { 15 | vector> tokens; 16 | }; 17 | 18 | struct TokenMachine 19 | { 20 | vector> tokens; 21 | 22 | Memento add_token(int value) 23 | { 24 | return add_token(make_shared(value)); 25 | } 26 | 27 | Memento add_token(const shared_ptr& token) 28 | { 29 | tokens.push_back(token); 30 | Memento m; 31 | for (auto t : tokens) 32 | m.tokens.emplace_back(make_shared(t->value)); 33 | return m; 34 | } 35 | 36 | void revert(const Memento& m) 37 | { 38 | tokens.clear(); 39 | for (auto t : m.tokens) 40 | tokens.emplace_back(make_shared(t->value)); 41 | } 42 | }; 43 | 44 | #include "gtest/gtest.h" 45 | //#include "helpers/iohelper.h" 46 | //#include "exercise.cpp" 47 | 48 | namespace { 49 | 50 | class Evaluate : public ::testing::Test {}; 51 | 52 | TEST_F(Evaluate, SingleTokenTest) { 53 | TokenMachine tm; 54 | auto m = tm.add_token(123); 55 | tm.add_token(456); 56 | tm.revert(m); 57 | ASSERT_EQ(1, tm.tokens.size()); 58 | ASSERT_EQ(123, tm.tokens[0]->value); 59 | } 60 | 61 | TEST_F(Evaluate, TwoTokenTest) 62 | { 63 | TokenMachine tm; 64 | tm.add_token(1); 65 | auto m = tm.add_token(2); 66 | tm.add_token(3); 67 | tm.revert(m); 68 | ASSERT_EQ(2, tm.tokens.size()); 69 | ASSERT_EQ(1, tm.tokens[0]->value) 70 | << "First toke should have value 1, you got " 71 | << tm.tokens[0]->value; 72 | ASSERT_EQ(2, tm.tokens[1]->value); 73 | } 74 | 75 | TEST_F(Evaluate, FiddledTokenTest) 76 | { 77 | TokenMachine tm; 78 | cout << "Made a token with value=111 and kept a reference\n"; 79 | auto token = make_shared(111); 80 | cout << "Added this token to the list\n"; 81 | tm.add_token(token); 82 | auto m = tm.add_token(222); 83 | cout << "Changed this token's value to 333 :)\n"; 84 | token->value = 333; 85 | tm.revert(m); 86 | 87 | ASSERT_EQ(2, tm.tokens.size()) 88 | << "At this point, token machine should have exactly " 89 | << "two tokens, you got " << tm.tokens.size(); 90 | 91 | ASSERT_EQ(111, tm.tokens[0]->value) 92 | << "You got the token value wrong here. " 93 | << "Hint: did you init the memento by-value?"; 94 | } 95 | 96 | } // namespace 97 | 98 | int main(int ac, char* av[]) 99 | { 100 | //::testing::GTEST_FLAG(catch_exceptions) = false; 101 | testing::InitGoogleTest(&ac, av); 102 | return RUN_ALL_TESTS(); 103 | } 104 | -------------------------------------------------------------------------------- /Structural/Flyweight/flyweight.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #include 7 | #include 8 | #include 9 | using namespace boost; 10 | using namespace flyweights; 11 | 12 | // coloring in the console by-letter vs using ranges 13 | 14 | // boost.flyweight 15 | 16 | // naive 17 | typedef uint32_t key; 18 | 19 | // mmorpg 20 | struct User 21 | { 22 | User(const string& first_name, const string& last_name) 23 | : first_name{add(first_name)}, last_name{add(last_name)} 24 | { 25 | } 26 | 27 | const string& get_first_name() const 28 | { 29 | return names.left.find(last_name)->second; 30 | } 31 | 32 | const string& get_last_name() const 33 | { 34 | return names.left.find(last_name)->second; 35 | } 36 | 37 | static void info() 38 | { 39 | for (auto entry : names.left) 40 | { 41 | cout << "Key: " << entry.first << ", Value: " << entry.second << endl; 42 | } 43 | } 44 | 45 | friend ostream& operator<<(ostream& os, const User& obj) 46 | { 47 | return os 48 | << "first_name: " << obj.first_name << " " << obj.get_first_name() 49 | << " last_name: " << obj.last_name << " " << obj.get_last_name(); 50 | } 51 | 52 | protected: 53 | static bimap names; 54 | static int seed; 55 | 56 | static key add(const string& s) 57 | { 58 | auto it = names.right.find(s); 59 | if (it == names.right.end()) 60 | { 61 | // add it 62 | key id = ++seed; 63 | names.insert({seed, s}); 64 | return id; 65 | } 66 | return it->second; 67 | } 68 | key first_name, last_name; 69 | }; 70 | 71 | key User::seed = 0; 72 | bimap User::names{}; 73 | 74 | void naive_flyweight() 75 | { 76 | User john_doe{ "John", "Doe" }; 77 | User jane_doe{ "Jane", "Doe" }; 78 | 79 | cout << "John " << john_doe << endl; 80 | cout << "Jane " << jane_doe << endl; 81 | 82 | User::info(); 83 | } 84 | 85 | struct User2 86 | { 87 | flyweight first_name, last_name; 88 | 89 | User2(const string &first_name, const string &last_name) 90 | : first_name(first_name), 91 | last_name(last_name) {} 92 | }; 93 | 94 | void boost_flyweight() 95 | { 96 | User2 user1{"John", "Smith"}; 97 | User2 user2{"Jane", "Smith"}; 98 | 99 | cout << user1.first_name << endl; 100 | 101 | cout << boolalpha 102 | << (&user1.first_name.get() == &user2.first_name.get()) << endl; 103 | cout << boolalpha 104 | << (&user1.last_name.get() == &user2.last_name.get()) << endl; 105 | } 106 | 107 | int main_() 108 | { 109 | naive_flyweight(); 110 | boost_flyweight(); 111 | 112 | getchar(); 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /Behavioral/Visitor/visitor_acyclic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // cyclic visitor: based on function overloading 7 | // works only on a stable hierarchy 8 | // acyclic visitor: based on RTTI 9 | // no hierarchy limitations, but slower 10 | 11 | template 12 | struct Visitor 13 | { 14 | virtual void visit(Visitable& obj) = 0; 15 | }; 16 | 17 | struct VisitorBase // marker interface 18 | { 19 | virtual ~VisitorBase() = default; 20 | }; 21 | 22 | struct Expression 23 | { 24 | virtual ~Expression() = default; 25 | 26 | virtual void accept(VisitorBase& obj) 27 | { 28 | using EV = Visitor; 29 | if (auto ev = dynamic_cast(&obj)) 30 | ev->visit(*this); 31 | } 32 | }; 33 | 34 | struct DoubleExpression : Expression{ 35 | double value; 36 | 37 | DoubleExpression(double value) : value(value) {} 38 | 39 | virtual void accept(VisitorBase& obj) 40 | { 41 | using DEV = Visitor; 42 | if (auto ev = dynamic_cast(&obj)) 43 | ev->visit(*this); 44 | } 45 | }; 46 | 47 | struct AdditionExpression : Expression 48 | { 49 | Expression *left, *right; 50 | 51 | AdditionExpression(Expression *left, Expression *right) : left(left), right(right) {} 52 | 53 | ~AdditionExpression() 54 | { 55 | delete left; 56 | delete right; 57 | } 58 | 59 | virtual void accept(VisitorBase& obj) 60 | { 61 | using AEV = Visitor; 62 | if (auto ev = dynamic_cast(&obj)) 63 | ev->visit(*this); 64 | } 65 | }; 66 | 67 | struct ExpressionPrinter : VisitorBase, 68 | Visitor, 69 | //Visitor, 70 | Visitor 71 | { 72 | void visit(Expression &obj) override 73 | { 74 | // fallback? 75 | } 76 | 77 | // can remove double visitor without failure 78 | // void visit(DoubleExpression &obj) override 79 | // { 80 | // oss << obj.value; 81 | // } 82 | 83 | void visit(AdditionExpression &obj) override 84 | { 85 | oss << "("; 86 | obj.left->accept(*this); 87 | oss << "+"; 88 | obj.right->accept(*this); 89 | oss << ")"; 90 | } 91 | 92 | string str() const { return oss.str(); } 93 | private: 94 | ostringstream oss; 95 | }; 96 | 97 | int main() 98 | { 99 | auto e = new AdditionExpression{ 100 | new DoubleExpression{1}, 101 | new AdditionExpression{ 102 | new DoubleExpression{2}, 103 | new DoubleExpression{3} 104 | } 105 | }; 106 | 107 | ExpressionPrinter ep; 108 | ep.visit(*e); 109 | cout << ep.str() << "\n"; 110 | 111 | //getchar(); 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /Structural/Decorator/DecoratorCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct Flower 9 | { 10 | virtual string str() = 0; 11 | }; 12 | 13 | struct Rose : Flower 14 | { 15 | string str() override { 16 | return "A rose"; 17 | } 18 | }; 19 | 20 | struct RedFlower : Flower 21 | { 22 | Flower& flower; 23 | 24 | RedFlower(Flower &flower) : flower(flower) {} 25 | 26 | string str() override 27 | { 28 | string s = flower.str(); 29 | if (s.find("red") != string::npos) return s; 30 | else if (s.find("blue") != string::npos) 31 | { 32 | return s + " and red"; 33 | } 34 | else return s + " that is red"; 35 | } 36 | }; 37 | 38 | struct BlueFlower : Flower 39 | { 40 | Flower& flower; 41 | 42 | BlueFlower(Flower &flower) : flower(flower) {} 43 | 44 | string str() override 45 | { 46 | string s = flower.str(); 47 | if (s.find("blue") != string::npos) return s; 48 | else if (s.find("red") != string::npos) 49 | { 50 | return s + " and blue"; 51 | } 52 | else return s + " that is blue"; 53 | } 54 | }; 55 | 56 | #include "gtest/gtest.h" 57 | 58 | //#include "helpers/iohelper.h" 59 | 60 | //#include "exercise.cpp" 61 | 62 | namespace 63 | { 64 | class Evaluate : public testing::Test 65 | { 66 | public: 67 | Rose rose; 68 | BlueFlower blue_rose{rose}; 69 | RedFlower red_rose{rose}; 70 | }; 71 | 72 | TEST_F(Evaluate, BaselineTest) 73 | { 74 | ASSERT_EQ("A rose", Rose{}.str()); 75 | } 76 | 77 | TEST_F(Evaluate, SingleColorTests) 78 | { 79 | ASSERT_EQ("A rose that is blue", blue_rose.str()); 80 | ASSERT_EQ("A rose that is red", red_rose.str()); 81 | } 82 | 83 | TEST_F(Evaluate, RepetitionTest) 84 | { 85 | ASSERT_EQ("A rose that is red", RedFlower{red_rose}.str()) 86 | << "This rose was made red twice, but you should print once."; 87 | } 88 | 89 | TEST_F(Evaluate, MultiColorTests) 90 | { 91 | ASSERT_EQ("A rose that is red and blue", 92 | BlueFlower{red_rose}.str()); 93 | ASSERT_EQ("A rose that is blue and red", 94 | RedFlower{blue_rose}.str()); 95 | } 96 | 97 | TEST_F(Evaluate, NestedRepetitionTest) 98 | { 99 | BlueFlower b_r_rose{red_rose}; 100 | RedFlower r_b_r_rose{b_r_rose}; 101 | ASSERT_EQ("A rose that is red and blue", 102 | r_b_r_rose.str()) 103 | << "This is a complicated case. I'm expecting that " 104 | << "a rose defined as Red{Blue{Red{Rose{}}}} is printed " 105 | << "as 'red and blue'."; 106 | } 107 | 108 | } // namespace 109 | 110 | int main(int ac, char* av[]) 111 | { 112 | testing::InitGoogleTest(&ac, av); 113 | return RUN_ALL_TESTS(); 114 | } -------------------------------------------------------------------------------- /Structural/NullObject/nullobject.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | //#include 6 | //using namespace boost; 7 | 8 | struct Logger 9 | { 10 | virtual ~Logger() = default; 11 | virtual void info(const string& s) = 0; 12 | virtual void warn(const string& s) = 0; 13 | }; 14 | 15 | struct OptionalLogger : Logger 16 | { 17 | shared_ptr impl; 18 | OptionalLogger(const shared_ptr& logger) 19 | : impl(logger) 20 | { 21 | } 22 | 23 | void info(const string& s) override 24 | { 25 | if (impl) impl->info(s); 26 | } 27 | 28 | void warn(const string& s) override 29 | { 30 | if (impl) impl->warn(s); 31 | } 32 | }; 33 | 34 | struct BankAccount 35 | { 36 | shared_ptr log; 37 | string name; 38 | int balance = 0; 39 | 40 | static shared_ptr no_logging; 41 | 42 | BankAccount(const string& name, int balance, const shared_ptr& logger = no_logging) 43 | : log{make_shared(logger)}, 44 | name{name}, 45 | balance{balance} 46 | { 47 | } 48 | 49 | void deposit(int amount) 50 | { 51 | balance += amount; 52 | log->info("Deposited $" /*+ lexical_cast(amount) 53 | + " to " + name + ", balance is now $" + lexical_cast(balance)*/); 54 | } 55 | 56 | void withdraw(int amount) 57 | { 58 | /*if (balance >= amount) 59 | { 60 | balance -= amount; 61 | log->info("Withdrew $" + lexical_cast(amount) 62 | + " from " + name + ", $" + lexical_cast(balance) + " left"); 63 | } 64 | else 65 | { 66 | log->warn("Tried to withdraw $" + lexical_cast(amount) + 67 | " from " + name + " but couldn't due to low balance"); 68 | }*/ 69 | } 70 | }; 71 | 72 | shared_ptr BankAccount::no_logging{}; 73 | 74 | struct ConsoleLogger : Logger 75 | { 76 | void info(const string& s) override 77 | { 78 | cout << "INFO: " << s << endl; 79 | } 80 | 81 | void warn(const string& s) override 82 | { 83 | cout << "WARNING!!! " << s << endl; 84 | } 85 | }; 86 | 87 | // similar idea 88 | struct EmailLogger : Logger 89 | { 90 | void info(const string& s) override; 91 | void warn(const string& s) override; 92 | }; 93 | 94 | int main() 95 | { 96 | //auto logger = make_shared(); 97 | 98 | struct NullLogger : Logger 99 | { 100 | void info(const string& s) override {} 101 | void warn(const string& s) override {} 102 | }; 103 | 104 | // this will crash 105 | shared_ptr empty_logger; 106 | auto logger = make_shared(); 107 | BankAccount account{ "primary account", 1000 }; 108 | 109 | account.deposit(2000); 110 | account.withdraw(2500); 111 | account.withdraw(1000); 112 | 113 | getchar(); 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /Behavioral/Visitor/VisitorCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct Value; 6 | struct AdditionExpression; 7 | struct MultiplicationExpression; 8 | 9 | struct ExpressionVisitor 10 | { 11 | virtual void accept(Value& value) = 0; 12 | virtual void accept(AdditionExpression& ae) = 0; 13 | virtual void accept(MultiplicationExpression& me) = 0; 14 | }; 15 | 16 | struct Expression 17 | { 18 | virtual void visit(ExpressionVisitor& ev) = 0; 19 | }; 20 | 21 | struct Value : Expression 22 | { 23 | int value; 24 | 25 | Value(int value) : value(value) {} 26 | 27 | void visit(ExpressionVisitor &ev) override 28 | { 29 | ev.accept(*this); 30 | } 31 | }; 32 | 33 | struct AdditionExpression : Expression 34 | { 35 | Expression &lhs, &rhs; 36 | 37 | AdditionExpression(Expression &lhs, Expression &rhs) : lhs(lhs), rhs(rhs) {} 38 | 39 | void visit(ExpressionVisitor &ev) override 40 | { 41 | ev.accept(*this); 42 | } 43 | }; 44 | 45 | struct MultiplicationExpression : Expression 46 | { 47 | Expression &lhs, &rhs; 48 | 49 | MultiplicationExpression(Expression &lhs, Expression &rhs) 50 | : lhs(lhs), rhs(rhs) {} 51 | 52 | void visit(ExpressionVisitor &ev) override 53 | { 54 | ev.accept(*this); 55 | } 56 | }; 57 | 58 | struct ExpressionPrinter : ExpressionVisitor 59 | { 60 | void accept(Value &value) override 61 | { 62 | oss << value.value; 63 | } 64 | 65 | void accept(AdditionExpression &ae) override 66 | { 67 | oss << "("; 68 | ae.lhs.visit(*this); 69 | oss << "+"; 70 | ae.rhs.visit(*this); 71 | oss << ")"; 72 | } 73 | 74 | void accept(MultiplicationExpression &me) override 75 | { 76 | me.lhs.visit(*this); 77 | oss << "*"; 78 | me.rhs.visit(*this); 79 | } 80 | 81 | string str() const { return oss.str(); } 82 | 83 | private: 84 | ostringstream oss; 85 | }; 86 | 87 | #include "gtest/gtest.h" 88 | 89 | //#include "helpers/iohelper.h" 90 | 91 | //#include "exercise.cpp" 92 | 93 | namespace { 94 | 95 | class Evaluate : public ::testing::Test {}; 96 | 97 | TEST_F(Evaluate, SimpleAddition) 98 | { 99 | Value v{2}; 100 | AdditionExpression simple{v,v}; 101 | ExpressionPrinter ep; 102 | ep.accept(simple); 103 | ASSERT_EQ("(2+2)", ep.str()); 104 | } 105 | 106 | TEST_F(Evaluate, ProductOfAdditionAndValue) 107 | { 108 | Value _2{2}; 109 | Value _3{3}; 110 | Value _4{4}; 111 | AdditionExpression ae{_2, _3}; 112 | MultiplicationExpression expr{ae, _4}; 113 | ExpressionPrinter ep; 114 | ep.accept(expr); 115 | ASSERT_EQ("(2+3)*4", ep.str()); 116 | } 117 | 118 | } // namespace 119 | 120 | // ERROR ON UDEMY'S END, POST AGAIN 121 | 122 | int main(int ac, char* av[]) 123 | { 124 | //::testing::GTEST_FLAG(catch_exceptions) = false; 125 | testing::InitGoogleTest(&ac, av); 126 | return RUN_ALL_TESTS(); 127 | } -------------------------------------------------------------------------------- /Behavioral/ChainOfResponsibility/cor_pointer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct Creature 6 | { 7 | string name; 8 | int attack, defense; 9 | 10 | Creature(const string& name, const int attack, const int defense) 11 | : name(name), 12 | attack(attack), 13 | defense(defense) 14 | { 15 | } 16 | 17 | 18 | friend ostream& operator<<(ostream& os, const Creature& obj) 19 | { 20 | return os 21 | << "name: " << obj.name 22 | << " attack: " << obj.attack 23 | << " defense: " << obj.defense; 24 | } 25 | }; 26 | 27 | class CreatureModifier 28 | { 29 | CreatureModifier* next{ nullptr }; // unique_ptr 30 | protected: 31 | Creature& creature; // pointer or shared_ptr 32 | public: 33 | explicit CreatureModifier(Creature& creature) 34 | : creature(creature) 35 | { 36 | } 37 | virtual ~CreatureModifier() = default; 38 | 39 | void add(CreatureModifier* cm) 40 | { 41 | if (next) next->add(cm); 42 | else next = cm; 43 | } 44 | 45 | // two approaches: 46 | 47 | // 1. Always call base handle(). There could be additional logic here. 48 | // 2. Only call base handle() when you cannot handle things yourself. 49 | 50 | virtual void handle() 51 | { 52 | if (next) next->handle(); 53 | } 54 | }; 55 | 56 | // 1. Double the creature's attack 57 | // 2. Increase defense by 1 unless power > 2 58 | // 3. No bonuses can be applied to this creature 59 | 60 | class NoBonusesModifier : public CreatureModifier 61 | { 62 | public: 63 | explicit NoBonusesModifier(Creature& creature) 64 | : CreatureModifier(creature) 65 | { 66 | } 67 | 68 | void handle() override 69 | { 70 | // nothing 71 | } 72 | }; 73 | 74 | class DoubleAttackModifier : public CreatureModifier 75 | { 76 | public: 77 | explicit DoubleAttackModifier(Creature& creature) 78 | : CreatureModifier(creature) 79 | { 80 | } 81 | 82 | void handle() override 83 | { 84 | creature.attack *= 2; 85 | CreatureModifier::handle(); 86 | } 87 | }; 88 | 89 | class IncreaseDefenseModifier : public CreatureModifier 90 | { 91 | public: 92 | explicit IncreaseDefenseModifier(Creature& creature) 93 | : CreatureModifier(creature) 94 | { 95 | } 96 | 97 | 98 | void handle() override 99 | { 100 | if (creature.attack <= 2) 101 | creature.defense += 1; 102 | CreatureModifier::handle(); 103 | } 104 | }; 105 | 106 | int main_() 107 | { 108 | Creature goblin{ "Goblin", 1, 1 }; 109 | CreatureModifier root{ goblin }; 110 | DoubleAttackModifier r1{ goblin }; 111 | DoubleAttackModifier r1_2{ goblin }; 112 | IncreaseDefenseModifier r2{ goblin }; 113 | //NoBonusesModifier nb{ goblin }; // effectively Command objects 114 | 115 | //root.add(&nb); 116 | root.add(&r1); 117 | root.add(&r1_2); 118 | root.add(&r2); 119 | 120 | root.handle(); // annoying 121 | 122 | cout << goblin << endl; 123 | 124 | //getchar(); 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /Behavioral/Command/command.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct BankAccount 7 | { 8 | int balance = 0; 9 | int overdraft_limit = -500; 10 | 11 | void deposit(int amount) 12 | { 13 | balance += amount; 14 | cout << "deposited " << amount << ", balance now " << 15 | balance << "\n"; 16 | } 17 | 18 | void withdraw(int amount) 19 | { 20 | if (balance - amount >= overdraft_limit) 21 | { 22 | balance -= amount; 23 | cout << "withdrew " << amount << ", balance now " << 24 | balance << "\n"; 25 | } 26 | } 27 | }; 28 | 29 | struct Command 30 | { 31 | virtual ~Command() = default; 32 | virtual void call() const = 0; 33 | virtual void undo() const = 0; 34 | }; 35 | 36 | // should really be BankAccountCommand 37 | struct BankAccountCommand : Command 38 | { 39 | BankAccount& account; 40 | enum Action { deposit, withdraw } action; 41 | int amount; 42 | 43 | BankAccountCommand(BankAccount& account, 44 | const Action action, const int amount) 45 | : account(account), action(action), amount(amount) {} 46 | 47 | void call() const override 48 | { 49 | switch (action) 50 | { 51 | case deposit: 52 | account.deposit(amount); 53 | break; 54 | case withdraw: 55 | account.withdraw(amount); 56 | break; 57 | default: break; 58 | } 59 | } 60 | 61 | void undo() const override 62 | { 63 | switch (action) 64 | { 65 | case withdraw: 66 | account.deposit(amount); 67 | break; 68 | case deposit: 69 | account.withdraw(amount); 70 | break; 71 | default: break; 72 | } 73 | } 74 | }; 75 | 76 | // vector doesn't have virtual dtor, but who cares? 77 | struct CompositeBankAccountCommand 78 | : vector, Command 79 | { 80 | CompositeBankAccountCommand(const initializer_list& items) 81 | : vector(items) {} 82 | 83 | void call() const override 84 | { 85 | for (auto& cmd : *this) 86 | cmd.call(); 87 | } 88 | 89 | void undo() const override 90 | { 91 | for (auto& cmd : *this) 92 | cmd.undo(); 93 | } 94 | }; 95 | 96 | int main_987() 97 | { 98 | BankAccount ba; 99 | /*vector commands{*/ 100 | CompositeBankAccountCommand commands { 101 | BankAccountCommand{ba, BankAccountCommand::deposit, 100}, 102 | BankAccountCommand{ba, BankAccountCommand::withdraw, 200} 103 | }; 104 | 105 | cout << ba.balance << endl; 106 | 107 | // apply all the commands 108 | /*for (auto& cmd : commands) 109 | { 110 | cmd.call(); 111 | }*/ 112 | commands.call(); 113 | 114 | cout << ba.balance << endl; 115 | 116 | /*for_each(commands.rbegin(), commands.rend(), 117 | [](const BankAccountCommand& cmd) { cmd.undo(); });*/ 118 | commands.undo(); 119 | 120 | cout << ba.balance << endl; 121 | 122 | getchar(); 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /Creational/Creational/BuilderCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct Field 7 | { 8 | string name, type; 9 | 10 | Field(const string& name, const string& type) 11 | : name{name}, 12 | type{type} 13 | { 14 | } 15 | 16 | 17 | friend ostream& operator<<(ostream& os, const Field& obj) 18 | { 19 | return os << obj.type << " " << obj.name << ";"; 20 | } 21 | }; 22 | 23 | struct Class 24 | { 25 | string name; 26 | vector fields; 27 | 28 | friend ostream& operator<<(ostream& os, const Class& obj) 29 | { 30 | os << "class " << obj.name << "\n{\n"; 31 | for (auto&& field : obj.fields) 32 | { 33 | os << " " << field << "\n"; 34 | } 35 | return os << "};\n"; 36 | } 37 | }; 38 | 39 | class CodeBuilder 40 | { 41 | Class the_class; 42 | public: 43 | CodeBuilder(const string& class_name) 44 | { 45 | the_class.name = class_name; 46 | } 47 | 48 | CodeBuilder& add_field(const string& name, const string& type) 49 | { 50 | the_class.fields.emplace_back(Field{ name, type }); 51 | return *this; 52 | } 53 | 54 | friend ostream& operator<<(ostream& os, const CodeBuilder& obj) 55 | { 56 | return os << obj.the_class; 57 | } 58 | }; 59 | 60 | #include "gtest/gtest.h" 61 | 62 | //#include "helpers/iohelper.h" 63 | 64 | //#include "exercise.cpp" 65 | 66 | #include 67 | #include 68 | #include 69 | #include 70 | 71 | // trim from start (in place) 72 | static inline void ltrim(std::string &s) { 73 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { 74 | return !std::isspace(ch); 75 | })); 76 | } 77 | 78 | // trim from end (in place) 79 | static inline void rtrim(std::string &s) { 80 | s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { 81 | return !std::isspace(ch); 82 | }).base(), s.end()); 83 | } 84 | 85 | // trim from both ends (in place) 86 | static inline void trim(std::string &s) { 87 | ltrim(s); 88 | rtrim(s); 89 | } 90 | 91 | // trim from start (copying) 92 | static inline std::string ltrim_copy(std::string s) { 93 | ltrim(s); 94 | return s; 95 | } 96 | 97 | // trim from end (copying) 98 | static inline std::string rtrim_copy(std::string s) { 99 | rtrim(s); 100 | return s; 101 | } 102 | 103 | namespace 104 | { 105 | class Evaluate : public testing::Test 106 | { 107 | }; 108 | 109 | TEST_F(Evaluate, EmptyTest) 110 | { 111 | CodeBuilder cb{ "Foo" }; 112 | ostringstream oss; 113 | oss << cb; 114 | auto printed = oss.str(); 115 | trim(printed); 116 | ASSERT_EQ("class Foo\n{\n};", printed); 117 | } 118 | 119 | TEST_F(Evaluate, PersonTest) 120 | { 121 | auto cb = CodeBuilder{ "Person" } 122 | .add_field("name", "string") 123 | .add_field("age", "int"); 124 | ostringstream oss; 125 | oss << cb; 126 | auto printed = oss.str(); 127 | trim(printed); 128 | ASSERT_EQ("class Person\n{\n string name;\n int age;\n};", printed); 129 | } 130 | } // namespace -------------------------------------------------------------------------------- /Behavioral/Memento/memento.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class Memento 8 | { 9 | int balance; 10 | public: 11 | Memento(int balance) 12 | : balance(balance) 13 | { 14 | } 15 | friend class BankAccount; 16 | friend class BankAccount2; 17 | }; 18 | 19 | class BankAccount 20 | { 21 | int balance = 0; 22 | public: 23 | explicit BankAccount(const int balance) 24 | : balance(balance) 25 | { 26 | } 27 | 28 | Memento deposit(int amount) 29 | { 30 | balance += amount; 31 | return { balance }; 32 | } 33 | 34 | void restore(const Memento& m) 35 | { 36 | balance = m.balance; 37 | } 38 | 39 | friend ostream& operator<<(ostream& os, const BankAccount& obj) 40 | { 41 | return os << "balance: " << obj.balance; 42 | } 43 | }; 44 | 45 | // undo/redo =================================== 46 | 47 | class BankAccount2 48 | { 49 | int balance = 0; 50 | vector> changes; 51 | int current; 52 | public: 53 | explicit BankAccount2(const int balance) 54 | : balance(balance) 55 | { 56 | changes.emplace_back(make_shared(balance)); 57 | current = 0; 58 | } 59 | 60 | shared_ptr deposit(int amount) 61 | { 62 | balance += amount; 63 | auto m = make_shared(balance); 64 | changes.push_back(m); 65 | ++current; 66 | return m; 67 | } 68 | 69 | void restore(const shared_ptr& m) 70 | { 71 | if (m) 72 | { 73 | balance = m->balance; 74 | changes.push_back(m); 75 | current = changes.size() - 1; 76 | } 77 | } 78 | 79 | shared_ptr undo() 80 | { 81 | if (current > 0) 82 | { 83 | --current; 84 | auto m = changes[current]; 85 | balance = m->balance; 86 | return m; 87 | } 88 | return{}; 89 | } 90 | 91 | shared_ptr redo() 92 | { 93 | if (current + 1 < changes.size()) 94 | { 95 | ++current; 96 | auto m = changes[current]; 97 | balance = m->balance; 98 | return m; 99 | } 100 | return{}; 101 | } 102 | 103 | friend ostream& operator<<(ostream& os, const BankAccount2& obj) 104 | { 105 | return os << "balance: " << obj.balance; 106 | } 107 | }; 108 | 109 | void memento() 110 | { 111 | BankAccount ba{ 100 }; 112 | auto m1 = ba.deposit(50); // 150 113 | auto m2 = ba.deposit(25); // 175 114 | cout << ba << "\n"; 115 | 116 | // undo to m1 117 | ba.restore(m1); 118 | cout << ba << "\n"; 119 | 120 | // redo 121 | ba.restore(m2); 122 | cout << ba << "\n"; 123 | } 124 | 125 | void undo_redo() 126 | { 127 | BankAccount2 ba{ 100 }; 128 | ba.deposit(50); 129 | ba.deposit(25); // 125 130 | cout << ba << "\n"; 131 | 132 | ba.undo(); 133 | cout << "Undo 1: " << ba << "\n"; 134 | ba.undo(); 135 | cout << "Undo 2: " << ba << "\n"; 136 | ba.redo(); 137 | cout << "Redo 2: " << ba << "\n"; 138 | 139 | ba.undo(); 140 | } 141 | 142 | int main() 143 | { 144 | // memento() 145 | undo_redo(); 146 | 147 | getchar(); 148 | return 0; 149 | } 150 | -------------------------------------------------------------------------------- /Behavioral/Visitor/single_double.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | #include "visitor.hpp" 10 | #include "model.hpp" 11 | 12 | struct HtmlVisitor : Visitor 13 | { 14 | void visit(const Paragraph& p) override 15 | { 16 | oss << "

    " << p.text << "

    \n"; 17 | } 18 | 19 | void visit(const ListItem& li) override 20 | { 21 | oss << "
  • " << li.text << "
  • \n"; 22 | } 23 | 24 | void visit(const List& l) override 25 | { 26 | oss << "
      \n"; 27 | for_each(l.begin(), l.end(), [&](const ListItem& li) 28 | { 29 | // only acceptable if we know that li is a ListItem 30 | this->visit(li); 31 | 32 | // if li was an Element, we would do 33 | //li.accept(*this); 34 | }); 35 | oss << "
    \n"; 36 | } 37 | 38 | string str() const override 39 | { 40 | return oss.str(); 41 | } 42 | 43 | private: 44 | ostringstream oss; 45 | }; 46 | 47 | struct MarkdownVisitor : Visitor 48 | { 49 | // dynamic_cast ifs 50 | void visit(const Element& e) 51 | { 52 | if (const Paragraph* p = dynamic_cast(&e)) 53 | { 54 | visit(*p); 55 | } else 56 | { 57 | // other cases 58 | } 59 | 60 | } 61 | 62 | void visit(const Paragraph& p) override 63 | { 64 | oss << p.text << "\n"; 65 | } 66 | 67 | void visit(const BoldParagraph& p) override 68 | { 69 | oss << "*" << p.text << "*\n"; 70 | } 71 | 72 | void visit(const ListItem& li) override 73 | { 74 | oss << " * " << li.text << "\n"; 75 | } 76 | 77 | void visit(const List& l) override 78 | { 79 | oss << "\n"; 80 | for_each(l.begin(), l.end(), [&](const ListItem& li) { this->visit(li); }); 81 | oss << "\n"; 82 | } 83 | 84 | 85 | void visit(const Div& div) override 86 | { 87 | oss << "
    \n"; 88 | for (auto e : div) 89 | { 90 | //visit(*e); 91 | e->accept(*this); 92 | } 93 | oss << "
    \n"; 94 | } 95 | 96 | string str() const override 97 | { 98 | return oss.str(); 99 | } 100 | 101 | private: 102 | ostringstream oss; 103 | }; 104 | 105 | // adding a new class requires total recompilation 106 | 107 | int main_(int argc, char* argv[]) 108 | { 109 | BoldParagraph p{ "Here are some colors" }; 110 | ListItem red{ "Red" }; 111 | ListItem green{ "Green" }; 112 | ListItem blue{ "Blue" }; 113 | List colors{ red,green,blue }; 114 | 115 | // single dispatch needs 1 item of information: which element to render to text 116 | // double dispatch needs 2 pieces of information: which element to render, and using which renderer 117 | 118 | vector document{ &p, &colors }; 119 | cout << "Textual representation: " << endl; 120 | 121 | MarkdownVisitor v; 122 | ostringstream oss; 123 | //for_each(document.begin(), document.end(), [&](const Element* e) 124 | //{ 125 | // // v.visit(*e) won't work :), but... 126 | // e->accept(v); 127 | //}); 128 | Div div{ &p, &colors }; 129 | div.print_html(oss); 130 | cout << oss.str() << endl; 131 | 132 | // everything is fine until we want another representation 133 | 134 | getchar(); 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /Behavioral/Observer/observer2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | #include 7 | using namespace boost; 8 | 9 | namespace { 10 | 11 | struct Person; 12 | 13 | struct PersonListener 14 | { 15 | virtual ~PersonListener() = default; 16 | virtual void person_changed(Person& p, const string& property_name, const any new_value) = 0; 17 | }; 18 | 19 | static mutex mtx; 20 | 21 | struct Person 22 | { 23 | explicit Person(int age) 24 | : age(age) 25 | { 26 | } 27 | 28 | int get_age() const 29 | { 30 | return age; 31 | } 32 | 33 | void set_age(const int age) 34 | { 35 | if (this->age == age) return; 36 | 37 | auto old_c_v = get_can_vote(); 38 | 39 | this->age = age; 40 | notify("age", this->age); 41 | 42 | auto new_c_v = get_can_vote(); 43 | if (old_c_v != new_c_v) 44 | { 45 | notify("can_vote", new_c_v); 46 | } 47 | } 48 | 49 | bool get_can_vote() const 50 | { 51 | return age >= 16; 52 | } 53 | 54 | void subscribe(PersonListener* pl) 55 | { 56 | lock_guard guard{ mtx }; 57 | 58 | // prevent existing references? 59 | if (find(begin(listeners), end(listeners), pl) == end(listeners)) 60 | listeners.push_back(pl); 61 | } 62 | void ubsubscribe(PersonListener* pl) 63 | { 64 | lock_guard guard{ mtx }; 65 | if (listeners.empty()) return; 66 | // multiple identical listeners? 67 | // erase-remove idiom? 68 | for (auto it = listeners.begin(); it != listeners.end(); ++it) 69 | { 70 | if (*it == pl) 71 | { 72 | *it = nullptr; // just mark as nullptr 73 | } 74 | } 75 | } 76 | private: 77 | int age; 78 | vector listeners; 79 | 80 | void notify(const string& property_name, const any new_value) 81 | { 82 | lock_guard guard{ mtx }; 83 | for (const auto listener : listeners) 84 | if (listener) 85 | listener->person_changed(*this, property_name, new_value); 86 | 87 | // erase-remove 88 | listeners.erase( 89 | remove(listeners.begin(), listeners.end(), nullptr), 90 | listeners.end() 91 | ); 92 | } 93 | 94 | // std::list (easier to remove elements) 95 | // concurrent_vector? yes, but no easy erase-remove 96 | }; 97 | 98 | struct ConsoleListener : PersonListener 99 | { 100 | void person_changed(Person& p, const string& property_name, 101 | const any new_value) override 102 | { 103 | cout << "person's " << property_name << " has been changed to "; 104 | if (property_name == "age") 105 | { 106 | cout << any_cast(new_value); 107 | } 108 | else if (property_name == "can_vote") 109 | { 110 | cout << any_cast(new_value); 111 | } 112 | cout << "\n"; 113 | } 114 | }; 115 | 116 | int main__x_() 117 | { 118 | Person p{ 14 }; 119 | ConsoleListener cl; 120 | p.subscribe(&cl); 121 | p.subscribe(&cl); // ignored 122 | p.set_age(15); 123 | p.set_age(16); 124 | p.ubsubscribe(&cl); 125 | p.set_age(17); 126 | 127 | 128 | getchar(); 129 | return 0; 130 | } 131 | 132 | } -------------------------------------------------------------------------------- /Behavioral/Strategy/StrategyCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct DiscriminantStrategy 8 | { 9 | virtual double calculate_discriminant(double a, double b, double c) = 0; 10 | }; 11 | 12 | struct OrdinaryDiscriminantStrategy : DiscriminantStrategy 13 | { 14 | double calculate_discriminant(double a, double b, double c) override { 15 | return b*b - 4*a*c; 16 | } 17 | }; 18 | 19 | struct RealDiscriminantStrategy : DiscriminantStrategy 20 | { 21 | double calculate_discriminant(double a, double b, double c) override { 22 | double result = b*b - 4*a*c; 23 | return result >= 0 ? result : numeric_limits::quiet_NaN(); 24 | } 25 | }; 26 | 27 | class QuadraticEquationSolver 28 | { 29 | DiscriminantStrategy& strategy; 30 | public: 31 | QuadraticEquationSolver(DiscriminantStrategy &strategy) : strategy(strategy) {} 32 | 33 | tuple, complex> solve(double a, double b, double c) 34 | { 35 | complex disc{strategy.calculate_discriminant(a,b,c), 0}; 36 | auto root_disc = sqrt(disc); 37 | return { 38 | (-b+root_disc) / (2*a), 39 | (-b-root_disc) / (2*a) }; 40 | }; 41 | }; 42 | 43 | #include "gtest/gtest.h" 44 | 45 | //#include "helpers/iohelper.h" 46 | 47 | //#include "exercise.cpp" 48 | 49 | namespace { 50 | 51 | class Evaluate : public ::testing::Test {}; 52 | 53 | TEST_F(Evaluate, PositiveTestOrdinaryStrategy) 54 | { 55 | OrdinaryDiscriminantStrategy strategy; 56 | QuadraticEquationSolver solver{strategy}; 57 | auto results = solver.solve(1,10,16); 58 | ASSERT_EQ(complex(-2,0), get<0>(results)); 59 | ASSERT_EQ(complex(-8,0), get<1>(results)); 60 | } 61 | 62 | TEST_F(Evaluate, PositiveTestRealStrategy) 63 | { 64 | RealDiscriminantStrategy strategy; 65 | QuadraticEquationSolver solver{strategy}; 66 | auto results = solver.solve(1,10,16); 67 | ASSERT_EQ(complex(-2,0), get<0>(results)); 68 | ASSERT_EQ(complex(-8,0), get<1>(results)); 69 | } 70 | 71 | TEST_F(Evaluate, NegativeTestOrdinaryStrategy) 72 | { 73 | OrdinaryDiscriminantStrategy strategy; 74 | QuadraticEquationSolver solver{strategy}; 75 | auto results = solver.solve(1,4,5); 76 | ASSERT_EQ(complex(-2,1), get<0>(results)); 77 | ASSERT_EQ(complex(-2,-1), get<1>(results)); 78 | } 79 | 80 | TEST_F(Evaluate, NegativeTestRealStrategy) 81 | { 82 | RealDiscriminantStrategy strategy; 83 | QuadraticEquationSolver solver{strategy}; 84 | auto results = solver.solve(1,4,5); 85 | auto x1 = get<0>(results); 86 | auto x2 = get<1>(results); 87 | ASSERT_TRUE(isnan(x1.real())); 88 | ASSERT_TRUE(isnan(x2.real())); 89 | ASSERT_TRUE(isnan(x1.imag())); 90 | ASSERT_TRUE(isnan(x2.imag())); 91 | } 92 | 93 | } // namespace 94 | 95 | // ERROR ON UDEMY'S END, POST AGAIN 96 | 97 | int main(int ac, char* av[]) 98 | { 99 | //::testing::GTEST_FLAG(catch_exceptions) = false; 100 | testing::InitGoogleTest(&ac, av); 101 | return RUN_ALL_TESTS(); 102 | } -------------------------------------------------------------------------------- /Behavioral/TemplateMethod/TemplateMethodCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct Creature 8 | { 9 | int attack, health; 10 | 11 | Creature(int attack, int health) : attack(attack), health(health) {} 12 | }; 13 | 14 | struct CardGame 15 | { 16 | vector creatures; 17 | 18 | CardGame(const vector &creatures) : creatures(creatures) {} 19 | 20 | // return -1 if there is no clear winner 21 | int combat(int creature1, int creature2) 22 | { 23 | Creature& first = creatures[creature1]; 24 | Creature& second = creatures[creature2]; 25 | hit(first, second); 26 | hit(second, first); 27 | bool first_alive = first.health > 0; 28 | bool second_alive = second.health > 0; 29 | if (first_alive == second_alive) return -1; 30 | return first_alive ? creature1 : creature2; 31 | } 32 | 33 | virtual void hit(Creature& attacker, Creature& other) = 0; 34 | }; 35 | 36 | struct TemporaryCardDamageGame : CardGame 37 | { 38 | TemporaryCardDamageGame(const vector &creatures) : CardGame(creatures) {} 39 | 40 | void hit(Creature &attacker, Creature &other) override { 41 | auto old_health = other.health; 42 | other.health -= attacker.attack; 43 | if (other.health > 0) other.health = old_health; 44 | } 45 | }; 46 | 47 | struct PermanentCardDamageGame : CardGame 48 | { 49 | PermanentCardDamageGame(const vector &creatures) : CardGame(creatures) {} 50 | 51 | void hit(Creature &attacker, Creature &other) override 52 | { 53 | other.health -= attacker.attack; 54 | } 55 | }; 56 | 57 | #include "gtest/gtest.h" 58 | 59 | //#include "helpers/iohelper.h" 60 | 61 | //#include "exercise.cpp" 62 | 63 | namespace { 64 | 65 | class Evaluate : public ::testing::Test {}; 66 | 67 | TEST_F(Evaluate, ImpasseTest) 68 | { 69 | Creature c1{1,2}; 70 | Creature c2{1,2}; 71 | TemporaryCardDamageGame game({c1,c2}); 72 | ASSERT_EQ(-1, game.combat(0,1)); 73 | ASSERT_EQ(-1, game.combat(0,1)); 74 | } 75 | 76 | TEST_F(Evaluate, TemporaryMurderTest) 77 | { 78 | Creature c1{1,1}; 79 | Creature c2{2,2}; 80 | TemporaryCardDamageGame game({c1,c2}); 81 | ASSERT_EQ(1, game.combat(0,1)); 82 | } 83 | 84 | TEST_F(Evaluate, DoubleMurderTest) 85 | { 86 | Creature c1{2,2}; 87 | Creature c2{2,2}; 88 | TemporaryCardDamageGame game({c1,c2}); 89 | ASSERT_EQ(-1, game.combat(0,1)) << "The expectation here is that two 2/2 creatures kill each other"; 90 | } 91 | 92 | TEST_F(Evaluate, PermanentDamageDeathTest) 93 | { 94 | Creature c1{1,2}; 95 | Creature c2{1,3}; 96 | PermanentCardDamageGame game({c1, c2}); 97 | ASSERT_EQ(-1, game.combat(0,1)) << "1/2 vs 1/3 should have no winner after first round of combat"; 98 | ASSERT_EQ(1, game.combat(0,1)) << "1/1 vs 1/2 here, so winner should be = 1"; 99 | } 100 | 101 | } // namespace 102 | 103 | int main(int ac, char* av[]) 104 | { 105 | //::testing::GTEST_FLAG(catch_exceptions) = false; 106 | testing::InitGoogleTest(&ac, av); 107 | return RUN_ALL_TESTS(); 108 | } -------------------------------------------------------------------------------- /Behavioral/State/msm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // back-end 7 | #include 8 | 9 | //front-end 10 | #include 11 | #include 12 | 13 | namespace msm = boost::msm; 14 | namespace mpl = boost::mpl; 15 | using namespace msm::front; 16 | 17 | vector state_names{ 18 | "off hook"s, 19 | "connecting"s, 20 | "connected"s, 21 | "on hold"s, 22 | "destroyed"s 23 | }; 24 | 25 | // transitions/events 26 | struct CallDialed {}; 27 | struct HungUp {}; 28 | struct CallConnected {}; 29 | struct PlacedOnHold {}; 30 | struct TakenOffHold {}; 31 | struct LeftMessage {}; 32 | struct PhoneThrownIntoWall {}; 33 | 34 | struct PhoneStateMachine : state_machine_def 35 | { 36 | bool angry{ true }; // start with false 37 | 38 | struct OffHook : state<> {}; 39 | struct Connecting : state<> 40 | { 41 | template 42 | void on_entry(Event const& evt, FSM&) 43 | { 44 | cout << "We are connecting..." << endl; 45 | } 46 | // also on_exit 47 | }; 48 | struct Connected : state<> {}; 49 | struct OnHold : state<> {}; 50 | struct PhoneDestroyed : state<> {}; 51 | 52 | struct PhoneBeingDestroyed 53 | { 54 | template 55 | void operator()(EVT const&, FSM&, SourceState&, TargetState&) 56 | { 57 | cout << "Phone breaks into a million pieces" << endl; 58 | } 59 | }; 60 | 61 | struct CanDestroyPhone 62 | { 63 | template 64 | bool operator()(EVT const&, FSM& fsm, SourceState&, TargetState&) 65 | { 66 | return fsm.angry; 67 | } 68 | }; 69 | 70 | // start, event, target, action, guard 71 | struct transition_table : mpl::vector < 72 | Row, 73 | Row, 74 | Row, 75 | Row 77 | > {}; 78 | 79 | // starting state 80 | typedef OffHook initial_state; 81 | 82 | // what happens if there's nowhere to go 83 | template 84 | void no_transition(Event const& e, FSM&, int state) 85 | { 86 | cout << "No transition from state " << state_names[state] 87 | << " on event " << typeid(e).name() << endl; 88 | } 89 | }; 90 | 91 | 92 | 93 | int main() 94 | { 95 | msm::back::state_machine phone; 96 | 97 | auto info = [&]() 98 | { 99 | auto i = phone.current_state()[0]; 100 | cout << "The phone is currently " << 101 | state_names[i] << "\n"; 102 | }; 103 | 104 | info(); 105 | phone.process_event(CallDialed{}); 106 | info(); 107 | phone.process_event(CallConnected{}); 108 | info(); 109 | phone.process_event(PlacedOnHold{}); 110 | info(); 111 | phone.process_event(PhoneThrownIntoWall{}); 112 | info(); 113 | 114 | // try process_event here :) 115 | phone.process_event(CallDialed{}); 116 | 117 | cout << "We are done using the phone" << "\n"; 118 | 119 | getchar(); 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /Behavioral/Visitor/visitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | #include 7 | #include 8 | using namespace boost; 9 | 10 | struct Literal; 11 | struct Addition; 12 | 13 | struct ExpressionVisitor 14 | { 15 | virtual void visit(const Literal& lit) = 0; 16 | virtual void visit(const Addition& add) = 0; 17 | }; 18 | 19 | struct PrintVisitor : ExpressionVisitor 20 | { 21 | void visit(const Literal& lit) override; 22 | void visit(const Addition& addition) override; 23 | 24 | string str() const 25 | { 26 | return oss.str(); 27 | } 28 | private: 29 | ostringstream oss; 30 | }; 31 | 32 | struct Expression 33 | { 34 | virtual ~Expression() 35 | { 36 | } 37 | 38 | virtual void print(ostringstream& oss) = 0; 39 | virtual void accept(PrintVisitor& pv) = 0; 40 | }; 41 | 42 | struct Literal : Expression 43 | { 44 | void print(ostringstream& oss) override 45 | { 46 | oss << lexical_cast(value); 47 | } 48 | 49 | explicit Literal(double value) 50 | : value{value} 51 | { 52 | } 53 | 54 | void accept(PrintVisitor& pv) override 55 | { 56 | pv.visit(*this); 57 | } 58 | 59 | double value; 60 | }; 61 | 62 | struct Addition : Expression 63 | { 64 | std::shared_ptr left, right; 65 | 66 | 67 | Addition(const std::shared_ptr& left, const std::shared_ptr& right) 68 | : left{left}, 69 | right{right} 70 | { 71 | } 72 | 73 | void accept(PrintVisitor& pv) override 74 | { 75 | pv.visit(*this); 76 | } 77 | 78 | void print(ostringstream& oss) override 79 | { 80 | oss << "("; 81 | left->print(oss); 82 | oss << " + "; 83 | right->print(oss); 84 | oss << ")"; 85 | } 86 | }; 87 | 88 | void PrintVisitor::visit(const Literal& literal) 89 | { 90 | this->oss << literal.value; 91 | } 92 | 93 | void PrintVisitor::visit(const Addition& addition) 94 | { 95 | this->oss << "("; 96 | addition.left->accept(*this); 97 | this->oss << " + "; 98 | addition.right->accept(*this); 99 | this->oss << ")"; 100 | } 101 | 102 | // dispatch - single, double, multiple 103 | 104 | // acyclic visitors 105 | 106 | // loki multimethods and https://ideone.com/8VxALs 107 | 108 | // https://github.com/Flast/multimethod 109 | // also one of the answers here http://stackoverflow.com/questions/23336586/did-the-loki-multimethods-make-it-into-c11 110 | 111 | std::shared_ptr lit(double value) 112 | { 113 | return make_shared(value); 114 | } 115 | 116 | std::shared_ptr add( 117 | const std::shared_ptr& left, 118 | const std::shared_ptr& right) 119 | { 120 | return make_shared(left, right); 121 | } 122 | 123 | void double_dispatch() 124 | { 125 | PrintVisitor pv; 126 | auto expr = add(add(lit(1), lit(2)), lit(3)); 127 | pv.visit(*expr); 128 | cout << pv.str() << endl; 129 | } 130 | 131 | void dynamic_visitor() 132 | { 133 | 134 | } 135 | 136 | void static_visitor() 137 | { 138 | ostringstream oss; // visitor 139 | add(add(lit(1), lit(2)), lit(3))->print(oss); 140 | cout << oss.str() << endl; 141 | } 142 | 143 | int main_() 144 | { 145 | static_visitor(); 146 | double_dispatch(); 147 | 148 | getchar(); 149 | return 0; 150 | } 151 | -------------------------------------------------------------------------------- /Behavioral/State/handmade.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | enum class State 8 | { 9 | off_hook, 10 | connecting, 11 | connected, 12 | on_hold, 13 | on_hook 14 | }; 15 | 16 | inline ostream& operator<<(ostream& os, const State& s) 17 | { 18 | switch (s) 19 | { 20 | case State::off_hook: 21 | os << "off the hook"; 22 | break; 23 | case State::connecting: 24 | os << "connecting"; 25 | break; 26 | case State::connected: 27 | os << "connected"; 28 | break; 29 | case State::on_hold: 30 | os << "on hold"; 31 | break; 32 | case State::on_hook: 33 | os << "on the hook"; 34 | break; 35 | } 36 | return os; 37 | } 38 | 39 | enum class Trigger 40 | { 41 | call_dialed, 42 | hung_up, 43 | call_connected, 44 | placed_on_hold, 45 | taken_off_hold, 46 | left_message, 47 | stop_using_phone 48 | }; 49 | 50 | inline ostream& operator<<(ostream& os, const Trigger& t) 51 | { 52 | switch (t) 53 | { 54 | case Trigger::call_dialed: 55 | os << "call dialed"; 56 | break; 57 | case Trigger::hung_up: 58 | os << "hung up"; 59 | break; 60 | case Trigger::call_connected: 61 | os << "call connected"; 62 | break; 63 | case Trigger::placed_on_hold: 64 | os << "placed on hold"; 65 | break; 66 | case Trigger::taken_off_hold: 67 | os << "taken off hold"; 68 | break; 69 | case Trigger::left_message: 70 | os << "left message"; 71 | break; 72 | case Trigger::stop_using_phone: 73 | os << "putting phone on hook"; 74 | break; 75 | default: break; 76 | } 77 | return os; 78 | } 79 | 80 | int main_f(char* argv[]) 81 | { 82 | map>> rules; 83 | 84 | rules[State::off_hook] = { 85 | {Trigger::call_dialed, State::connecting}, 86 | {Trigger::stop_using_phone, State::on_hook} 87 | }; 88 | 89 | rules[State::connecting] = { 90 | {Trigger::hung_up, State::off_hook}, 91 | {Trigger::call_connected, State::connected} 92 | }; 93 | 94 | rules[State::connected] = { 95 | {Trigger::left_message, State::off_hook}, 96 | {Trigger::hung_up, State::off_hook}, 97 | {Trigger::placed_on_hold, State::on_hold} 98 | }; 99 | 100 | rules[State::on_hold] = { 101 | {Trigger::taken_off_hold, State::connected}, 102 | {Trigger::hung_up, State::off_hook} 103 | }; 104 | 105 | State currentState{ State::off_hook }, 106 | exitState{ State::on_hook }; 107 | 108 | while (true) 109 | { 110 | cout << "The phone is currently " << currentState << endl; 111 | select_trigger: 112 | cout << "Select a trigger:" << "\n"; 113 | 114 | int i = 0; 115 | for (auto item : rules[currentState]) 116 | { 117 | cout << i++ << ". " << item.first << "\n"; 118 | } 119 | 120 | int input; 121 | cin >> input; 122 | if (input < 0 || (input+1) > rules[currentState].size()) 123 | { 124 | cout << "Incorrect option. Please try again." << "\n"; 125 | goto select_trigger; 126 | } 127 | 128 | currentState = rules[currentState][input].second; 129 | if (currentState == exitState) break; 130 | } 131 | 132 | cout << "We are done using the phone" << "\n"; 133 | 134 | getchar(); 135 | getchar(); 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /Behavioral/ChainOfResponsibility/CoRCodingExercise.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct Creature; 6 | struct Game 7 | { 8 | vector creatures; 9 | }; 10 | 11 | struct StatQuery 12 | { 13 | enum Statistic { attack, defense } statistic; 14 | int result; 15 | }; 16 | 17 | struct Creature 18 | { 19 | protected: 20 | Game& game; 21 | int base_attack, base_defense; 22 | 23 | public: 24 | Creature(Game &game, int base_attack, int base_defense) : game(game), base_attack(base_attack), 25 | base_defense(base_defense) {} 26 | 27 | virtual int get_attack() = 0; 28 | virtual int get_defense() = 0; 29 | virtual void query(void* source, StatQuery& sq) = 0; 30 | }; 31 | 32 | class Goblin : public Creature 33 | { 34 | int get_statistic(StatQuery::Statistic stat) 35 | { 36 | StatQuery q{stat,0}; 37 | for (auto c : game.creatures) 38 | c->query(this, q); 39 | return q.result; 40 | } 41 | public: 42 | Goblin(Game &game, int base_attack, int base_defense) : Creature(game, base_attack, base_defense) {} 43 | 44 | Goblin(Game &game) : Creature(game, 1, 1) {} 45 | 46 | int get_attack() override { 47 | return get_statistic(StatQuery::attack); 48 | } 49 | 50 | int get_defense() override { 51 | return get_statistic(StatQuery::defense); 52 | } 53 | 54 | void query(void *source, StatQuery &sq) override { 55 | if (source == this) 56 | { 57 | switch (sq.statistic) 58 | { 59 | case StatQuery::attack: 60 | sq.result += base_attack; 61 | break; 62 | case StatQuery::defense: 63 | sq.result += base_defense; 64 | break; 65 | } 66 | } else 67 | { 68 | if (sq.statistic == StatQuery::defense) 69 | { 70 | sq.result++; 71 | } 72 | } 73 | } 74 | }; 75 | 76 | class GoblinKing : public Goblin 77 | { 78 | public: 79 | GoblinKing(Game &game) : Goblin(game, 3, 3) {} 80 | 81 | void query(void *source, StatQuery &sq) override { 82 | if (source != this && sq.statistic == StatQuery::attack) 83 | { 84 | sq.result++; 85 | } 86 | else Goblin::query(source, sq); 87 | } 88 | }; 89 | 90 | #include "gtest/gtest.h" 91 | 92 | //#include "helpers/iohelper.h" 93 | 94 | //#include "exercise.cpp" 95 | 96 | namespace 97 | { 98 | class Evaluate : public testing::Test 99 | { 100 | public: 101 | }; 102 | 103 | TEST_F(Evaluate, ManyGoblinsTest) 104 | { 105 | Game game; 106 | Goblin goblin{game}; 107 | game.creatures.push_back(&goblin); 108 | 109 | cout << "Checking that a baseline goblin is a 1/1...\n"; 110 | 111 | ASSERT_EQ(1, goblin.get_attack()); 112 | ASSERT_EQ(1, goblin.get_defense()); 113 | 114 | cout << "Adding a second goblin, now they should be 1/2...\n"; 115 | Goblin goblin2{game}; 116 | game.creatures.push_back(&goblin2); 117 | 118 | ASSERT_EQ(1, goblin.get_attack()); 119 | ASSERT_EQ(2, goblin.get_defense()); 120 | 121 | cout << "Adding a goblin king, now a goblin should be 2/3...\n"; 122 | GoblinKing goblin3{game}; 123 | game.creatures.push_back(&goblin3); 124 | 125 | ASSERT_EQ(2, goblin.get_attack()); 126 | ASSERT_EQ(3, goblin.get_defense()); 127 | } 128 | 129 | } // namespace 130 | 131 | int main(int ac, char* av[]) 132 | { 133 | testing::InitGoogleTest(&ac, av); 134 | return RUN_ALL_TESTS(); 135 | } -------------------------------------------------------------------------------- /Behavioral/Observer/observer_book.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | #include 10 | using namespace Concurrency; 11 | 12 | #include 13 | 14 | template struct Observer; 15 | 16 | template 17 | struct Observable 18 | { 19 | typedef mutex mutex_t; 20 | 21 | void notify(T& source, const string& name) 22 | { 23 | vector*> observers_copy; 24 | { 25 | lock_guard lock{ mtx }; 26 | observers_copy = observers; 27 | } 28 | for (auto obs : observers_copy) 29 | if (obs) 30 | obs->field_changed(source, name); 31 | 32 | observers.erase( 33 | remove(observers.begin(), observers.end(), nullptr), 34 | observers.end()); 35 | } 36 | /*void notify(T& source, const string& name) 37 | { 38 | lock_guard lock{ mtx }; 39 | for (auto obs : observers) 40 | if (obs) 41 | obs->field_changed(source, name); 42 | 43 | observers.erase( 44 | remove(observers.begin(), observers.end(), nullptr), 45 | observers.end()); 46 | }*/ 47 | void subscribe(Observer* f) 48 | { 49 | lock_guard lock{ mtx }; 50 | observers.push_back(f); 51 | } 52 | void unsubscribe(Observer* o) 53 | { 54 | lock_guard lock{ mtx }; 55 | auto it = find(observers.begin(), observers.end(), o); 56 | if (it != observers.end()) 57 | *it = nullptr; // cannot do this for a set 58 | } 59 | private: 60 | vector*> observers; 61 | mutex_t mtx; 62 | }; 63 | 64 | template struct Observer 65 | { 66 | virtual void field_changed(T& source, const string& field_name) = 0; 67 | }; 68 | 69 | struct Person : Observable 70 | { 71 | explicit Person(const int age) 72 | : age(age) 73 | { 74 | } 75 | 76 | int get_age() const 77 | { 78 | return age; 79 | } 80 | 81 | void set_age(const int age) 82 | { 83 | if (this->age == age) return; 84 | 85 | auto old_can_vote = can_vote(); 86 | this->age = age; 87 | 88 | notify(*this, "age"); 89 | 90 | if (old_can_vote != can_vote()) 91 | notify(*this, "can_vote"); 92 | } 93 | 94 | bool can_vote() const 95 | { 96 | return age >= 16; 97 | } 98 | 99 | private: 100 | int age; 101 | }; 102 | 103 | struct Creature 104 | { 105 | 106 | }; 107 | 108 | struct ConsolePersonObserver : Observer 109 | { 110 | void field_changed(Person& source, const string& field_name) override 111 | { 112 | cout << "Person's " << field_name << " has changed to " 113 | << source.get_age() << ".\n"; 114 | } 115 | }; 116 | 117 | struct TrafficAdministration : Observer 118 | { 119 | void TrafficAdministration::field_changed( 120 | Person& source, const string& field_name) override 121 | { 122 | if (field_name == "age") 123 | { 124 | if (source.get_age() < 17) 125 | cout << "Whoa there, you are not old enough to drive!\n"; 126 | else 127 | { 128 | // oh, ok, they are old enough, let's not monitor them anymore 129 | cout << "We no longer care!\n"; 130 | source.unsubscribe(this); 131 | } 132 | } 133 | } 134 | }; 135 | 136 | 137 | 138 | int main() 139 | { 140 | cout << "observer book" << endl; 141 | 142 | /*Person p{ 20 }; 143 | ConsolePersonObserver cpo; 144 | p.subscribe(&cpo); 145 | p.set_age(21); 146 | p.set_age(22);*/ 147 | 148 | Person p{ 10 }; 149 | TrafficAdministration o; 150 | p.subscribe(&o); 151 | p.set_age(16); 152 | p.set_age(17); 153 | p.set_age(21); 154 | 155 | getchar(); 156 | return 0; 157 | } 158 | --------------------------------------------------------------------------------