├── .gitignore ├── LICENSE ├── README.md ├── adapter.h ├── bridge.h ├── builder.h ├── chainOfResponsibility.h ├── command.h ├── composition.h ├── decorator.h ├── expressionProcessor.h ├── factory.h ├── flyweight.h ├── iterator.h ├── mediator.h ├── memento.h ├── observer.h ├── prototype.h ├── proxy.h ├── singleton.h ├── state.h ├── strategy.h └── template.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Benjamin Mahr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Design Patterns In Modern C++ 2 | Pattern coding exercise solutions based upon an [Udemy](https://www.udemy.com) Lecture about [Patterns in Modern C++](https://www.udemy.com/patterns-cplusplus/) (C++11) by [Dmitri Nesteruk](https://www.udemy.com/user/dmitrinesteruk/).\ 3 | This repsoitory is meant to be as an introductionary help into patterns with C++. Some of the example implementations are better, some are not. If you have any improvements feel free to open a pull request. 4 | 5 | ## Patterns 6 | - [Builder](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/builder.h) 7 | - [Factories](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/factory.h) 8 | - [Prototype](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/prototype.h) 9 | - [Singleton](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/singleton.h) 10 | - [Adapter](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/adapter.h) 11 | - [Bridge](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/bridge.h) 12 | - [Composite](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/composition.h) 13 | - [Decorator](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/decorator.h) 14 | - [Flyweight](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/flyweight.h) 15 | - [Proxy](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/proxy.h) 16 | - [Chain of Responsibility](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/chainOfResponsibility.h) 17 | - [Command](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/command.h) 18 | - [Interpreter](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/expressionProcessor.h) 19 | - [Iterator](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/iterator.h) 20 | - [Mediator](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/mediator.h) 21 | - [Memento](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/memento.h) 22 | - [Observer](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/observer.h) 23 | - [State](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/state.h) 24 | - [Strategy](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/strategy.h) 25 | - [Template Method](https://github.com/Ben1980/DesignPatternsInModernCPP/blob/master/template.h) 26 | -------------------------------------------------------------------------------- /adapter.h: -------------------------------------------------------------------------------- 1 | struct Square 2 | { 3 | int side{ 0 }; 4 | 5 | 6 | explicit Square(const int side) 7 | : side(side) 8 | { 9 | } 10 | }; 11 | 12 | struct Rectangle 13 | { 14 | virtual int width() const = 0; 15 | virtual int height() const = 0; 16 | 17 | int area() const 18 | { 19 | return width() * height(); 20 | } 21 | }; 22 | 23 | 24 | // Adapt the interface of a square to the interface of a rectangle 25 | // Example: 26 | // Square square(2); 27 | // SquareToRectangleAdapter adapter(square); 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 | -------------------------------------------------------------------------------- /bridge.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Decoupling abstraction from implementation and therefore can help enforceing encapsulation 6 | struct Renderer 7 | { 8 | virtual string what_to_render_as() const = 0; 9 | }; 10 | 11 | struct Shape 12 | { 13 | std::string name; 14 | const Renderer& renderer; 15 | 16 | Shape(const Renderer& renderer): renderer{renderer} { 17 | } 18 | 19 | std::string str() const 20 | { 21 | std::ostringstream oss; 22 | oss << "Drawing " << name << " as " 23 | << renderer.what_to_render_as(); 24 | return oss.str(); 25 | } 26 | }; 27 | 28 | struct Triangle : Shape 29 | { 30 | explicit Triangle(const Renderer& renderer) 31 | : Shape{renderer} 32 | { 33 | name = "Triangle"; 34 | } 35 | }; 36 | 37 | struct Square : Shape 38 | { 39 | explicit Square(const Renderer& renderer) 40 | : Shape{renderer} 41 | { 42 | name = "Square"; 43 | } 44 | }; 45 | 46 | struct RasterRenderer : Renderer 47 | { 48 | string what_to_render_as() const override 49 | { 50 | return "pixels"; 51 | } 52 | }; 53 | 54 | struct VectorRenderer : Renderer 55 | { 56 | string what_to_render_as() const override 57 | { 58 | return "lines"; 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /builder.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // CodeBuilder builds strings based on fields added by the user via add_field(...) 7 | // Example: CodeBuilder{"Person"}.add_field("name", "string").add_field("age", "int"); 8 | class CodeBuilder 9 | { 10 | public: 11 | CodeBuilder(const std::string& class_name) 12 | : className(class_name) 13 | { 14 | } 15 | 16 | CodeBuilder& add_field(const std::string& name, const std::string& type) 17 | { 18 | fields.push_back({name, type}); 19 | 20 | return *this; 21 | } 22 | 23 | friend std::ostream& operator<<(std::ostream& os, const CodeBuilder& obj) 24 | { 25 | os << "class " << obj.className << "\n{\n"; 26 | for(auto field : obj.fields) { 27 | os << " " << field.second << " " << field.first << ";\n"; 28 | } 29 | os << "};"; 30 | 31 | return os; 32 | } 33 | 34 | private: 35 | std::string className; 36 | std::vector> fields; 37 | }; 38 | -------------------------------------------------------------------------------- /chainOfResponsibility.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Creature; 4 | struct Game 5 | { 6 | std::vector creatures; 7 | }; 8 | 9 | struct StatQuery 10 | { 11 | enum Statistic { attack, defense } statistic; 12 | int result; 13 | }; 14 | 15 | struct Creature 16 | { 17 | protected: 18 | Game& game; 19 | int base_attack, base_defense; 20 | 21 | public: 22 | Creature(Game &game, int base_attack, int base_defense) : game(game), base_attack(base_attack), 23 | base_defense(base_defense) {} 24 | virtual int get_attack() = 0; 25 | virtual int get_defense() = 0; 26 | virtual void query(void* source, StatQuery& sq) = 0; 27 | }; 28 | 29 | class Goblin : public Creature 30 | { 31 | public: 32 | Goblin(Game &game, int base_attack, int base_defense) : Creature(game, base_attack, base_defense) {} 33 | 34 | Goblin(Game &game) : Creature(game, 1, 1) {} 35 | 36 | int get_attack() override { 37 | return get_statistic(StatQuery::attack); 38 | } 39 | 40 | int get_defense() override { 41 | return get_statistic(StatQuery::defense); 42 | } 43 | 44 | void query(void *source, StatQuery &sq) override { 45 | if (source == this) 46 | { 47 | switch (sq.statistic) 48 | { 49 | case StatQuery::attack: 50 | sq.result += base_attack; 51 | break; 52 | case StatQuery::defense: 53 | sq.result += base_defense; 54 | break; 55 | } 56 | } else 57 | { 58 | if (sq.statistic == StatQuery::defense) 59 | { 60 | sq.result++; 61 | } 62 | } 63 | } 64 | 65 | private: 66 | int get_statistic(StatQuery::Statistic stat) { 67 | StatQuery q{stat,0}; 68 | for (auto c : game.creatures) 69 | c->query(this, q); 70 | return q.result; 71 | } 72 | }; 73 | 74 | class GoblinKing : public Goblin 75 | { 76 | public: 77 | GoblinKing(Game &game) : Goblin(game, 3, 3) {} 78 | void query(void *source, StatQuery &sq) override { 79 | if (source != this && sq.statistic == StatQuery::attack) 80 | { 81 | sq.result++; 82 | } 83 | else Goblin::query(source, sq); 84 | } 85 | }; 86 | -------------------------------------------------------------------------------- /command.h: -------------------------------------------------------------------------------- 1 | struct Command 2 | { 3 | enum Action { deposit, withdraw } action; 4 | int amount{0}; 5 | bool success{false}; 6 | }; 7 | 8 | struct Account 9 | { 10 | int balance{0}; 11 | 12 | void process(Command& cmd) 13 | { 14 | switch (cmd.action) { 15 | case Command::deposit: 16 | balance += cmd.amount; 17 | cmd.success = true; 18 | break; 19 | case Command::withdraw: 20 | cmd.success = (balance >= cmd.amount); 21 | if (cmd.success) balance -= cmd.amount; 22 | break; 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /composition.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct ContainsIntegers { 7 | virtual int sum() const = 0; 8 | }; 9 | 10 | struct SingleValue : public ContainsIntegers 11 | { 12 | int value{ 0 }; 13 | 14 | SingleValue() = default; 15 | 16 | explicit SingleValue(const int value) 17 | : value{value} 18 | { 19 | } 20 | 21 | int sum() const override { 22 | return value; 23 | } 24 | }; 25 | 26 | struct ManyValues : std::vector, public ContainsIntegers 27 | { 28 | void add(const int value) 29 | { 30 | push_back(value); 31 | } 32 | 33 | int sum() const override { 34 | int sum = 0; 35 | for(const int &element : *this) { 36 | sum += element; 37 | } 38 | 39 | return sum; 40 | } 41 | }; 42 | 43 | // Example: 44 | // SingleValue single{1}; 45 | // ManyValues many; 46 | // many.add(2); 47 | // many.add(3); 48 | // std::cout << sum({&single, &many}) << std::endl; 49 | int sum(const std::vector items) { 50 | int sum = 0; 51 | for(ContainsIntegers *element : items) { 52 | sum += element->sum(); 53 | } 54 | 55 | return sum; 56 | } 57 | -------------------------------------------------------------------------------- /decorator.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // A Rose can be decorated with colors 4 | // Example: 5 | // Rose rose; 6 | // RedFlower red_rose(rose); 7 | // RedFlower red_red_rose(red_rose); 8 | // BlueFlower blue_red_rose(red_rose); 9 | // BlueFlower blue_rose(rose); 10 | // RedFlower red_blue_red_rose(blue_red_rose); 11 | 12 | struct Flower 13 | { 14 | virtual std::string str() = 0; 15 | }; 16 | 17 | struct Rose : Flower 18 | { 19 | std::string str() override { 20 | return "A rose"; 21 | } 22 | }; 23 | 24 | struct RedFlower : Flower 25 | { 26 | Flower &mFlower; 27 | const std::string color; 28 | 29 | RedFlower(Flower &flower) : mFlower(flower), color("red") { } 30 | 31 | std::string str() override { 32 | std::string ret = mFlower.str(); 33 | 34 | if (ret.find("that is") == std::string::npos) { 35 | ret += " that is " + color; 36 | } 37 | else if (ret.find(color) == std::string::npos) { 38 | ret += " and " + color; 39 | } 40 | 41 | return ret; 42 | } 43 | }; 44 | 45 | struct BlueFlower : Flower 46 | { 47 | Flower &mFlower; 48 | const std::string color; 49 | 50 | BlueFlower(Flower &flower) : mFlower(flower), color("blue") { } 51 | 52 | std::string str() override { 53 | std::string ret = mFlower.str(); 54 | 55 | if (ret.find("that is") == std::string::npos) { 56 | ret += " that is " + color; 57 | } 58 | else if (ret.find(color) == std::string::npos) { 59 | ret += " and " + color; 60 | } 61 | 62 | return ret; 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /expressionProcessor.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | inline std::vector split(const std::string& stringToSplit) 8 | { 9 | std::vector result; 10 | size_t pos = 0, lastPos = 0; 11 | while ((pos = stringToSplit.find_first_of("+-", lastPos)) != std::string::npos) 12 | { 13 | result.push_back(stringToSplit.substr(lastPos, pos-lastPos+1)); 14 | lastPos = pos+1; 15 | } 16 | result.push_back(stringToSplit.substr(lastPos)); 17 | return result; 18 | } 19 | 20 | struct ExpressionProcessor 21 | { 22 | std::map variables; 23 | 24 | enum NextOp 25 | { 26 | nothing, 27 | plus, 28 | minus 29 | }; 30 | 31 | int calculate(const std::string& expression) 32 | { 33 | int current; 34 | auto next_op = nothing; 35 | 36 | auto parts = split(expression); 37 | 38 | std::cout << "parts (" << parts.size() << "): "; 39 | for (auto& part : parts) 40 | std::cout << "`" << part << "` "; 41 | std::cout << std::endl; 42 | 43 | for (auto& part : parts) 44 | { 45 | auto no_op = split(part); 46 | auto first = no_op[0]; 47 | int value, z; 48 | 49 | try 50 | { 51 | value = stoi(first); 52 | } 53 | catch (const std::invalid_argument&) 54 | { 55 | if (first.length() == 1 && 56 | variables.find(first[0]) != variables.end()) 57 | { 58 | value = variables[first[0]]; 59 | } 60 | else return 0; 61 | } 62 | 63 | switch (next_op) 64 | { 65 | case nothing: 66 | current = value; 67 | break; 68 | case plus: 69 | current += value; 70 | break; 71 | case minus: 72 | current -= value; 73 | break; 74 | } 75 | 76 | if (*part.rbegin() == '+') next_op = plus; 77 | else if (*part.rbegin() == '-') next_op = minus; 78 | } 79 | 80 | return current; 81 | } 82 | }; 83 | -------------------------------------------------------------------------------- /factory.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Person 5 | { 6 | int id; 7 | std::string name; 8 | }; 9 | 10 | // Example: 11 | // PersonFactory personFactory; 12 | // Person p1 = personFactory.create_person("Tom"); 13 | class PersonFactory 14 | { 15 | public: 16 | Person create_person(const std::string& name) 17 | { 18 | return {instanceCounter++, name}; 19 | } 20 | 21 | private: 22 | int instanceCounter = 0; 23 | }; 24 | -------------------------------------------------------------------------------- /flyweight.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // External data representation, e.g. map, vector, etc 6 | // Example: 7 | // Sentence sentence("hello world"); 8 | // sentence[1].capitalize = true; 9 | class Sentence 10 | { 11 | public: 12 | Sentence(const std::string& text) { 13 | std::istringstream stream(text); 14 | std::string s; 15 | 16 | while (std::getline(stream, s, ' ')) { 17 | sentence.push_back( {s, false} ); 18 | } 19 | } 20 | 21 | struct WordToken 22 | { 23 | std::string word; 24 | bool capitalize; 25 | }; 26 | 27 | WordToken& operator[](size_t index) 28 | { 29 | return sentence[index]; 30 | } 31 | 32 | std::string str() const 33 | { 34 | std::string str; 35 | 36 | for(size_t tokeIndex = 0; tokeIndex < sentence.size(); ++tokeIndex) { 37 | WordToken token = sentence[tokeIndex]; 38 | 39 | if(token.capitalize) { 40 | for(size_t charIndex = 0; charIndex < token.word.length(); ++charIndex) { 41 | auto c = std::toupper(token.word[charIndex]); 42 | token.word[charIndex] = c; 43 | } 44 | } 45 | 46 | str += token.word + (tokeIndex < sentence.size()-1 ? " " : ""); 47 | } 48 | 49 | return str; 50 | } 51 | 52 | private: 53 | std::vector sentence; 54 | }; 55 | -------------------------------------------------------------------------------- /iterator.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct Node 6 | { 7 | T value; 8 | Node *left{nullptr}, *right{nullptr}, *parent{nullptr}; 9 | 10 | Node(T value) : value(value) {} 11 | 12 | Node(T value, Node *left, Node *right) : value(value), left(left), right(right) { 13 | left->parent = right->parent = this; 14 | } 15 | 16 | // traverse the node and its children preorder 17 | // and put all the results into `result` 18 | void preorder_traversal(std::vector*>& result) 19 | { 20 | preorder_traversal_impl(this, result); 21 | } 22 | 23 | private: 24 | void preorder_traversal_impl(Node *current, std::vector*>& result) { 25 | result.push_back(current); 26 | if(current->left) preorder_traversal_impl(current->left, result); 27 | if(current->right) preorder_traversal_impl(current->right, result); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /mediator.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct IParticipant { 4 | virtual void setValue(int val) = 0; 5 | }; 6 | 7 | struct Mediator { 8 | std::vector participants; 9 | 10 | void broadcast(IParticipant* participant, int value) { 11 | for(auto * p : participants) { 12 | if(p != participant) { 13 | p->setValue(value); 14 | } 15 | } 16 | } 17 | }; 18 | 19 | struct Participant : IParticipant 20 | { 21 | int value{0}; 22 | Mediator& mediator; 23 | 24 | Participant(Mediator &mediator) : mediator(mediator) 25 | { 26 | mediator.participants.push_back(this); 27 | } 28 | 29 | void say(int value) 30 | { 31 | mediator.broadcast(this, value); 32 | } 33 | 34 | void setValue(int val) override { 35 | value = val; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /memento.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Token 6 | { 7 | int value; 8 | 9 | Token(int value) : value(value) {} 10 | }; 11 | 12 | struct Memento 13 | { 14 | std::vector> tokens; 15 | }; 16 | 17 | struct TokenMachine 18 | { 19 | std::vector> tokens; 20 | 21 | Memento add_token(int value) 22 | { 23 | return add_token(std::make_shared(value)); 24 | } 25 | 26 | // adds the token to the set of tokens and returns the 27 | // snapshot of the entire system 28 | Memento add_token(const std::shared_ptr& token) 29 | { 30 | if(token) { 31 | tokens.push_back(token); 32 | } 33 | Memento memento; 34 | for(auto t : tokens) { 35 | memento.tokens.emplace_back(std::make_shared(t->value)); 36 | } 37 | 38 | return memento; 39 | } 40 | 41 | // reverts the system to a state represented by the token 42 | void revert(const Memento& m) 43 | { 44 | tokens.clear(); 45 | for(auto t : m.tokens) { 46 | tokens.emplace_back(std::make_shared(t->value)); 47 | } 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /observer.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct IRat 7 | { 8 | virtual void rat_enters(IRat* sender) = 0; 9 | virtual void rat_dies(IRat* sender) = 0; 10 | virtual void notify(IRat* target) = 0; 11 | }; 12 | 13 | struct Game 14 | { 15 | vector rats; 16 | virtual void fire_rat_enters(IRat* sender) 17 | { 18 | for (auto rat : rats) rat->rat_enters(sender); 19 | } 20 | virtual void fire_rat_dies(IRat* sender) 21 | { 22 | for (auto rat : rats) rat->rat_dies(sender); 23 | } 24 | virtual void fire_notify(IRat* target) 25 | { 26 | for (auto rat : rats) rat->notify(target); 27 | } 28 | }; 29 | 30 | struct Rat : IRat 31 | { 32 | Game& game; 33 | int attack{1}; 34 | 35 | Rat(Game &game) : game(game) 36 | { 37 | game.rats.push_back(this); 38 | game.fire_rat_enters(this); 39 | } 40 | 41 | ~Rat() 42 | { 43 | game.fire_rat_dies(this); 44 | game.rats.erase(std::remove(game.rats.begin(),game.rats.end(),this)); 45 | } 46 | 47 | void rat_enters(IRat *sender) override { 48 | if (sender != this) 49 | { 50 | ++attack; 51 | game.fire_notify(sender); 52 | } 53 | } 54 | 55 | void rat_dies(IRat *sender) override { 56 | --attack; 57 | } 58 | 59 | void notify(IRat *target) override { 60 | if (target == this) ++attack; 61 | } 62 | }; 63 | -------------------------------------------------------------------------------- /prototype.h: -------------------------------------------------------------------------------- 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 | // Create new instances by cloning a prototype 11 | // Example: 12 | // Line line(new Point(), new Point(2,2)); 13 | // Line copy = line.deep_copy(); 14 | struct Line 15 | { 16 | Point *start, *end; 17 | 18 | Line(Point* const start, Point* const end) 19 | : start(start), end(end) 20 | { 21 | } 22 | 23 | ~Line() 24 | { 25 | delete start; 26 | delete end; 27 | } 28 | 29 | Line deep_copy() const 30 | { 31 | return {new Point(start->x, start->y), 32 | new Point(end->x, end->y)}; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /proxy.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Person 4 | { 5 | friend class ResponsiblePerson; 6 | int age; 7 | public: 8 | Person(int age) : age(age) {} 9 | 10 | int get_age() const { return age; } 11 | void set_age(int age) { this->age=age; } 12 | 13 | std::string drink() const { return "drinking"; } 14 | std::string drive() const { return "driving"; } 15 | std::string drink_and_drive() const { return "driving while drunk"; } 16 | }; 17 | 18 | // Acts as simple proxy of Person 19 | class ResponsiblePerson 20 | { 21 | public: 22 | ResponsiblePerson(const Person &person) : person(person) {} 23 | 24 | int get_age() const { return person.get_age(); } 25 | void set_age(int age) { person.set_age(age); } 26 | 27 | std::string drink() const { return person.get_age() > 17 ? person.drink() : "too young"; } 28 | std::string drive() const { return person.get_age() > 17 ? person.drive() : "too young"; } 29 | std::string drink_and_drive() const { return "dead"; } 30 | private: 31 | Person person; 32 | }; 33 | -------------------------------------------------------------------------------- /singleton.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct SingletonTester 4 | { 5 | template 6 | bool is_singleton(std::function factory) 7 | { 8 | auto * object1 = factory(); 9 | auto * object2 = factory(); 10 | 11 | return object1 == object2; 12 | } 13 | }; 14 | 15 | // Example of Singleton implementation with std::function and lambda 16 | // struct SingletonTest { 17 | // int a{42}; 18 | // }; 19 | // 20 | // std::function wrongSingletonFactory = []() -> SingletonTest* { return new SingletonTest; }; 21 | // 22 | // std::function correctSingletonFactory = []() -> SingletonTest* { 23 | // static SingletonTest test; 24 | // return &test; 25 | // }; 26 | // 27 | // could be also done with 28 | // auto correctSingletonFactoryWithAuto = []() -> SingletonTest* { 29 | // static SingletonTest test; 30 | // return &test; 31 | // }; 32 | // 33 | // SingletonTester tester; 34 | // std::cout << tester.is_singleton(wrongSingletonFactory) << std::endl; //false 35 | // std::cout << tester.is_singleton(correctSingletonFactory) << std::endl; //true 36 | -------------------------------------------------------------------------------- /state.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class CombinationLock 6 | { 7 | std::vector combination; 8 | int digits_entered{0}; 9 | bool failed{false}; 10 | 11 | void reset() 12 | { 13 | status = "LOCKED"; 14 | digits_entered = 0; 15 | failed = false; 16 | } 17 | 18 | public: 19 | std::string status; 20 | 21 | CombinationLock(const std::vector &combination) : combination(combination){ 22 | reset(); 23 | } 24 | 25 | void enter_digit(int digit) 26 | { 27 | if (status == "LOCKED") status = ""; 28 | status += std::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 | -------------------------------------------------------------------------------- /strategy.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 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 res = b*b - 4*a*c; 23 | 24 | if(res < 0) { 25 | return numeric_limits::quiet_NaN(); 26 | } 27 | 28 | return res; 29 | } 30 | }; 31 | 32 | class QuadraticEquationSolver 33 | { 34 | DiscriminantStrategy& strategy; 35 | public: 36 | QuadraticEquationSolver(DiscriminantStrategy &strategy) : strategy(strategy) {} 37 | 38 | std::tuple, std::complex> solve(double a, double b, double c) 39 | { 40 | std::complex disc{strategy.calculate_discriminant(a,b,c), 0}; 41 | auto root_disc = sqrt(disc); 42 | return { 43 | (-b+root_disc) / (2*a), 44 | (-b-root_disc) / (2*a) }; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /template.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct Creature 7 | { 8 | int attack, health; 9 | 10 | Creature(int attack, int health) : attack(attack), health(health) {} 11 | }; 12 | 13 | struct CardGame 14 | { 15 | std::vector creatures; 16 | 17 | CardGame(const std::vector &creatures) : creatures(creatures) {} 18 | 19 | // return the index of the creature that won (is a live) 20 | // example: 21 | // - creature1 alive, creature2 dead, return creature1 22 | // - creature1 dead, creature2 alive, return creature2 23 | // - no clear winner: return -1 24 | int combat(int creature1, int creature2) 25 | { 26 | hit(creatures[creature1], creatures[creature2]); 27 | hit(creatures[creature2], creatures[creature1]); 28 | 29 | bool c1Alive = creatures[creature1].health > 0; 30 | bool c2Alive = creatures[creature2].health > 0; 31 | if (c1Alive == c2Alive) return -1; 32 | return c1Alive ? creature1 : creature2; 33 | } 34 | 35 | virtual void hit(Creature& attacker, Creature& other) = 0; 36 | }; 37 | 38 | struct TemporaryCardDamageGame : CardGame 39 | { 40 | TemporaryCardDamageGame(const std::vector &creatures) : CardGame(creatures) {} 41 | 42 | void hit(Creature &attacker, Creature &other) override { 43 | double oldHealth = other.health; 44 | other.health -= attacker.attack; 45 | if(other.health > 0) { 46 | other.health = oldHealth; 47 | } 48 | } 49 | }; 50 | 51 | struct PermanentCardDamageGame : CardGame 52 | { 53 | PermanentCardDamageGame(const std::vector &creatures) : CardGame(creatures) {} 54 | 55 | void hit(Creature &attacker, Creature &other) override 56 | { 57 | other.health -= attacker.attack; 58 | } 59 | }; 60 | --------------------------------------------------------------------------------