From d994d720a70f07d1ece2bd3993e8cb69918244b9 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 11 Sep 2019 11:17:09 -0500 Subject: [PATCH 01/36] Initial commit --- src/AbstractFactory/Conceptual/main.cpp | 241 ++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 src/AbstractFactory/Conceptual/main.cpp diff --git a/src/AbstractFactory/Conceptual/main.cpp b/src/AbstractFactory/Conceptual/main.cpp new file mode 100644 index 0000000..461a530 --- /dev/null +++ b/src/AbstractFactory/Conceptual/main.cpp @@ -0,0 +1,241 @@ +#include +#include + +/** + * EN: Abstract Factory Design Pattern + * + * Intent: Lets you produce families of related objects without specifying their + * concrete classes. + * + * RU: Паттерн Абстрактная Фабрика + * + * Назначение: Предоставляет интерфейс для создания семейств связанных или + * зависимых объектов без привязки к их конкретным классам. + */ +/** + * EN: The Abstract Factory interface declares a set of methods that return + * different abstract products. These products are called a family and are + * related by a high-level theme or concept. Products of one family are usually + * able to collaborate among themselves. A family of products may have several + * variants, but the products of one variant are incompatible with products of + * another. + * + * RU: Интерфейс Абстрактной Фабрики объявляет набор методов, которые возвращают + * различные абстрактные продукты. Эти продукты называются семейством и связаны + * темой или концепцией высокого уровня. Продукты одного семейства обычно могут + * взаимодействовать между собой. Семейство продуктов может иметь несколько + * вариаций, но продукты одной вариации несовместимы с продуктами другой. + */ + +class AbstractProductA; +class AbstractProductB; + +class AbstractFactory +{ +public: + virtual AbstractProductA* createProductA() const = 0; + virtual AbstractProductB* createProductB() const = 0; +}; + +/** + * EN: Each distinct product of a product family should have a base interface. + * All variants of the product must implement this interface. + * + * RU: Каждый отдельный продукт семейства продуктов должен иметь базовый + * интерфейс. Все вариации продукта должны реализовывать этот интерфейс. + */ + +class AbstractProductA +{ +public: + virtual ~AbstractProductA(){}; // define as needed + virtual std::string usefulFunctionA() const = 0; +}; + + +/** + * EN: Concrete Products are created by corresponding Concrete Factories. + * + * RU: Конкретные продукты создаются соответствующими Конкретными Фабриками. + */ + +class ConcreteProductA1 : public AbstractProductA +{ +public: + std::string usefulFunctionA() const override + { + return "The result of the product A1."; + } +}; + +class ConcreteProductA2 : public AbstractProductA +{ + std::string usefulFunctionA() const override + { + return "The result of the product A2."; + } +}; + +/** + * EN: Here's the the base interface of another product. All products can + * interact with each other, but proper interaction is possible only between + * products of the same concrete variant. + * + * RU: Базовый интерфейс другого продукта. Все продукты могут взаимодействовать + * друг с другом, но правильное взаимодействие возможно только между продуктами + * одной и той же конкретной вариации. + */ + +class AbstractProductB +{ + /** + * EN: Product B is able to do its own thing... + * + * RU: Продукт B способен работать самостоятельно... + */ +public: + virtual ~AbstractProductB(){}; // define as needed + + virtual std::string usefulFunctionB() const = 0; + /** + * EN: ...but it also can collaborate with the ProductA. + * + * The Abstract Factory makes sure that all products it creates are of the + * same variant and thus, compatible. + * + * RU: ...а также взаимодействовать с Продуктами Б той же вариации. + * + * Абстрактная Фабрика гарантирует, что все продукты, которые она создает, + * имеют одинаковую вариацию и, следовательно, совместимы. + */ + virtual std::string anotherUsefulFunctionB(const AbstractProductA *collaborator) const = 0; +}; + +/** + * EN: Concrete Products are created by corresponding Concrete Factories. + * + * RU: Конкретные Продукты создаются соответствующими Конкретными Фабриками. + */ + +class ConcreteProductB1: public AbstractProductB{ + public: + + std::string usefulFunctionB() const override{ + return "The result of the product B1."; + } + /** + * EN: The variant, Product B1, is only able to work correctly with the + * variant, Product A1. Nevertheless, it accepts any instance of + * AbstractProductA as an argument. + * + * RU: Продукт B1 может корректно работать только с Продуктом A1. Тем не + * менее, он принимает любой экземпляр Абстрактного Продукта А в качестве + * аргумента. + */ + std::string anotherUsefulFunctionB(const AbstractProductA* collaborator) const override{ + const std::string result= collaborator->usefulFunctionA(); + return "The result of the B1 collaborating with "+ result; + } +}; + +class ConcreteProductB2: public AbstractProductB{ + public: + std::string usefulFunctionB() const override{ + return "The result of the product B2."; + } + + /** + * EN: The variant, Product B2, is only able to work correctly with the + * variant, Product A2. Nevertheless, it accepts any instance of + * AbstractProductA as an argument. + * + * RU: Продукт B2 может корректно работать только с Продуктом A2. Тем не + * менее, он принимает любой экземпляр Абстрактного Продукта А в качестве + * аргумента. + */ + std::string anotherUsefulFunctionB(const AbstractProductA* collaborator) const override{ + const std::string result= collaborator->usefulFunctionA(); + return "The result of the B2 collaborating with "+ result; + } +}; + + + +/** + * EN: Concrete Factories produce a family of products that belong to a single + * variant. The factory guarantees that resulting products are compatible. Note + * that signatures of the Concrete Factory's methods return an abstract product, + * while inside the method a concrete product is instantiated. + * + * RU: Конкретная Фабрика производит семейство продуктов одной вариации. Фабрика + * гарантирует совместимость полученных продуктов. Обратите внимание, что + * сигнатуры методов Конкретной Фабрики возвращают абстрактный продукт, в то + * время как внутри метода создается экземпляр конкретного продукта. + */ + +class ConcreteFactory1 : public AbstractFactory +{ +public: + AbstractProductA* createProductA() const override + { + return new ConcreteProductA1(); + } + + AbstractProductB* createProductB() const override + { + return new ConcreteProductB1(); + } +}; +/** + * EN: Each Concrete Factory has a corresponding product variant. + * + * RU: Каждая Конкретная Фабрика имеет соответствующую вариацию продукта. + */ + +class ConcreteFactory2 : public AbstractFactory +{ +public: + AbstractProductA* createProductA() const override + { + return new ConcreteProductA2(); + } + + AbstractProductB* createProductB() const override + { + return new ConcreteProductB2(); + } +}; + + + + +/** + * EN: The client code works with factories and products only through abstract + * types: AbstractFactory and AbstractProduct. This lets you pass any factory or + * product subclass to the client code without breaking it. + * + * RU: Клиентский код работает с фабриками и продуктами только через абстрактные + * типы: Абстрактная Фабрика и Абстрактный Продукт. Это позволяет передавать + * любой подкласс фабрики или продукта клиентскому коду, не нарушая его. + */ + +void ClientCode(const AbstractFactory* factory){ + const AbstractProductA* productA =factory->createProductA(); + const AbstractProductB* productB =factory->createProductB(); + std::cout << productB->usefulFunctionB() << "\n"; + std::cout << productB->anotherUsefulFunctionB(productA) << "\n"; + delete productA; + delete productB; +} + +int main(){ + std::cout << "Client: Testing client code with the first factory type:\n"; + ConcreteFactory1* f1= new ConcreteFactory1(); + ClientCode(f1); + delete f1; + std::cout << "Client: Testing the same client code with the second factory type:\n"; + ConcreteFactory2* f2= new ConcreteFactory2(); + ClientCode(f2); + delete f2; + return 0; +} \ No newline at end of file From 0388f6055f385a36347b24c54bb9e13726a64ec4 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 11 Sep 2019 11:27:46 -0500 Subject: [PATCH 02/36] format output --- src/AbstractFactory/Conceptual/Output.txt | 8 ++++++++ src/AbstractFactory/Conceptual/main.cpp | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 src/AbstractFactory/Conceptual/Output.txt diff --git a/src/AbstractFactory/Conceptual/Output.txt b/src/AbstractFactory/Conceptual/Output.txt new file mode 100644 index 0000000..9ef339f --- /dev/null +++ b/src/AbstractFactory/Conceptual/Output.txt @@ -0,0 +1,8 @@ + +Client: Testing client code with the first factory type: +The result of the product B1. +The result of the B1 collaborating with the (The result of the product A1.) + +Client: Testing the same client code with the second factory type: +The result of the product B2. +The result of the B2 collaborating with the (The result of the product A2.) \ No newline at end of file diff --git a/src/AbstractFactory/Conceptual/main.cpp b/src/AbstractFactory/Conceptual/main.cpp index 461a530..78b6627 100644 --- a/src/AbstractFactory/Conceptual/main.cpp +++ b/src/AbstractFactory/Conceptual/main.cpp @@ -134,7 +134,7 @@ class ConcreteProductB1: public AbstractProductB{ */ std::string anotherUsefulFunctionB(const AbstractProductA* collaborator) const override{ const std::string result= collaborator->usefulFunctionA(); - return "The result of the B1 collaborating with "+ result; + return "The result of the B1 collaborating with ( "+ result+" )"; } }; @@ -155,7 +155,7 @@ class ConcreteProductB2: public AbstractProductB{ */ std::string anotherUsefulFunctionB(const AbstractProductA* collaborator) const override{ const std::string result= collaborator->usefulFunctionA(); - return "The result of the B2 collaborating with "+ result; + return "The result of the B2 collaborating with ( "+ result+" )"; } }; @@ -233,6 +233,7 @@ int main(){ ConcreteFactory1* f1= new ConcreteFactory1(); ClientCode(f1); delete f1; + std::cout << std::endl; std::cout << "Client: Testing the same client code with the second factory type:\n"; ConcreteFactory2* f2= new ConcreteFactory2(); ClientCode(f2); From bf58a87c40d1c01cbe20f0153f31d8d55e8dc048 Mon Sep 17 00:00:00 2001 From: ederfduran <42628372+ederfduran@users.noreply.github.com> Date: Mon, 16 Sep 2019 10:16:43 -0500 Subject: [PATCH 03/36] Update README.md --- README.md | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d34e6b5..e6cca38 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,41 @@ It contains C++ examples for all classic GoF design patterns. Each pattern inclu ## Requirements -TODO - +The examples were written as cross platform console application using c++11. It means that you should be able to compile and execute those examples with any recent compiler. + +we recommend working with Visual Studio Code because it is a lightweight and cross-platform tool .It is a very complete IDE and is available for free (https://code.visualstudio.com/). You may need to install c++ extension and the compiler you prefer (The extension is still in preview and its focus is code editing, navigation, and debugging support for C and C++). For more information on how to use VSCode with c++ refer to: https://code.visualstudio.com/docs/languages/cpp . + +For code execution in VSCode you will need to set up your task first. An example using g++ : + +```sh +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "g++ -g -std=c++11 Conceptual/main.cc -o main", + "group":{ + "kind": "build", + "isDefault": true + }, + "problemMatcher":"$gcc" + } + ] +} +``` +Then you just need to start the executable. ## Contributor's Guide -TODO +I appreciate any help, whether it's a simple fix of a typo or a whole new example. Just make a fork, make your change and submit a pull request. + +Here's a style guide which might help you to keep your changes consistent with the rest of the project's code: + +1. All code should match the [Google style guide]. +2. Aim to put all code within one .cc file. Yes, I realize that it's not how it supposed to be done in production. However, it helps people to understand examples better, since all code fits into one screen. +3. The comments doesn't follow the style guide for compatibility reasons withe other language examples. + ## License @@ -23,3 +52,7 @@ TODO This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License. Creative Commons License + + + +[Google style guide]: From 76bc6e494f6a1c7323416813fec7a901395707c6 Mon Sep 17 00:00:00 2001 From: ederfduran <42628372+ederfduran@users.noreply.github.com> Date: Mon, 16 Sep 2019 10:22:07 -0500 Subject: [PATCH 04/36] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e6cca38..0d43c27 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ For code execution in VSCode you will need to set up your task first. An example ] } ``` -Then you just need to start the executable. +Then you just need to start the executable.In case you have some doubts here you have an useful [tutorial] using vscode. ## Contributor's Guide @@ -56,3 +56,4 @@ This work is licensed under a Creative Commons Attribution-NonCommercial-NoDeriv [Google style guide]: +[tutorial]: From a18acefa1f131f5f256bf357c158747896a7ab45 Mon Sep 17 00:00:00 2001 From: ederfduran <42628372+ederfduran@users.noreply.github.com> Date: Mon, 16 Sep 2019 10:26:33 -0500 Subject: [PATCH 05/36] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d43c27..e13413e 100644 --- a/README.md +++ b/README.md @@ -56,4 +56,4 @@ This work is licensed under a Creative Commons Attribution-NonCommercial-NoDeriv [Google style guide]: -[tutorial]: +[tutorial]: From 7cfebe1aa186baee41eb30f4976fe0eced4dbdf8 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Mon, 16 Sep 2019 10:29:45 -0500 Subject: [PATCH 06/36] google std changes --- .../Conceptual/{main.cpp => main.cc} | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) rename src/AbstractFactory/Conceptual/{main.cpp => main.cc} (84%) diff --git a/src/AbstractFactory/Conceptual/main.cpp b/src/AbstractFactory/Conceptual/main.cc similarity index 84% rename from src/AbstractFactory/Conceptual/main.cpp rename to src/AbstractFactory/Conceptual/main.cc index 78b6627..4a9b5b6 100644 --- a/src/AbstractFactory/Conceptual/main.cpp +++ b/src/AbstractFactory/Conceptual/main.cc @@ -33,8 +33,8 @@ class AbstractProductB; class AbstractFactory { public: - virtual AbstractProductA* createProductA() const = 0; - virtual AbstractProductB* createProductB() const = 0; + virtual AbstractProductA* CreateProductA() const = 0; + virtual AbstractProductB* CreateProductB() const = 0; }; /** @@ -47,9 +47,14 @@ class AbstractFactory class AbstractProductA { + /** + * EN: Define virtual destructor in case you need it. + * + * RU: + */ public: - virtual ~AbstractProductA(){}; // define as needed - virtual std::string usefulFunctionA() const = 0; + virtual ~AbstractProductA(){}; + virtual std::string UsefulFunctionA() const = 0; }; @@ -62,7 +67,7 @@ class AbstractProductA class ConcreteProductA1 : public AbstractProductA { public: - std::string usefulFunctionA() const override + std::string UsefulFunctionA() const override { return "The result of the product A1."; } @@ -70,7 +75,7 @@ class ConcreteProductA1 : public AbstractProductA class ConcreteProductA2 : public AbstractProductA { - std::string usefulFunctionA() const override + std::string UsefulFunctionA() const override { return "The result of the product A2."; } @@ -94,9 +99,9 @@ class AbstractProductB * RU: Продукт B способен работать самостоятельно... */ public: - virtual ~AbstractProductB(){}; // define as needed + virtual ~AbstractProductB(){}; - virtual std::string usefulFunctionB() const = 0; + virtual std::string UsefulFunctionB() const = 0; /** * EN: ...but it also can collaborate with the ProductA. * @@ -108,7 +113,7 @@ class AbstractProductB * Абстрактная Фабрика гарантирует, что все продукты, которые она создает, * имеют одинаковую вариацию и, следовательно, совместимы. */ - virtual std::string anotherUsefulFunctionB(const AbstractProductA *collaborator) const = 0; + virtual std::string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const = 0; }; /** @@ -120,7 +125,7 @@ class AbstractProductB class ConcreteProductB1: public AbstractProductB{ public: - std::string usefulFunctionB() const override{ + std::string UsefulFunctionB() const override{ return "The result of the product B1."; } /** @@ -132,15 +137,15 @@ class ConcreteProductB1: public AbstractProductB{ * менее, он принимает любой экземпляр Абстрактного Продукта А в качестве * аргумента. */ - std::string anotherUsefulFunctionB(const AbstractProductA* collaborator) const override{ - const std::string result= collaborator->usefulFunctionA(); + std::string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const override{ + const std::string result= collaborator.UsefulFunctionA(); return "The result of the B1 collaborating with ( "+ result+" )"; } }; class ConcreteProductB2: public AbstractProductB{ public: - std::string usefulFunctionB() const override{ + std::string UsefulFunctionB() const override{ return "The result of the product B2."; } @@ -153,8 +158,8 @@ class ConcreteProductB2: public AbstractProductB{ * менее, он принимает любой экземпляр Абстрактного Продукта А в качестве * аргумента. */ - std::string anotherUsefulFunctionB(const AbstractProductA* collaborator) const override{ - const std::string result= collaborator->usefulFunctionA(); + std::string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const override{ + const std::string result= collaborator.UsefulFunctionA(); return "The result of the B2 collaborating with ( "+ result+" )"; } }; @@ -176,12 +181,12 @@ class ConcreteProductB2: public AbstractProductB{ class ConcreteFactory1 : public AbstractFactory { public: - AbstractProductA* createProductA() const override + AbstractProductA* CreateProductA() const override { return new ConcreteProductA1(); } - AbstractProductB* createProductB() const override + AbstractProductB* CreateProductB() const override { return new ConcreteProductB1(); } @@ -195,12 +200,12 @@ class ConcreteFactory1 : public AbstractFactory class ConcreteFactory2 : public AbstractFactory { public: - AbstractProductA* createProductA() const override + AbstractProductA* CreateProductA() const override { return new ConcreteProductA2(); } - AbstractProductB* createProductB() const override + AbstractProductB* CreateProductB() const override { return new ConcreteProductB2(); } @@ -219,24 +224,24 @@ class ConcreteFactory2 : public AbstractFactory * любой подкласс фабрики или продукта клиентскому коду, не нарушая его. */ -void ClientCode(const AbstractFactory* factory){ - const AbstractProductA* productA =factory->createProductA(); - const AbstractProductB* productB =factory->createProductB(); - std::cout << productB->usefulFunctionB() << "\n"; - std::cout << productB->anotherUsefulFunctionB(productA) << "\n"; - delete productA; - delete productB; +void ClientCode(const AbstractFactory& factory){ + const AbstractProductA* product_a =factory.CreateProductA(); + const AbstractProductB* product_b =factory.CreateProductB(); + std::cout << product_b->UsefulFunctionB() << "\n"; + std::cout << product_b->AnotherUsefulFunctionB(*product_a) << "\n"; + delete product_a; + delete product_b; } int main(){ std::cout << "Client: Testing client code with the first factory type:\n"; ConcreteFactory1* f1= new ConcreteFactory1(); - ClientCode(f1); + ClientCode(*f1); delete f1; std::cout << std::endl; std::cout << "Client: Testing the same client code with the second factory type:\n"; ConcreteFactory2* f2= new ConcreteFactory2(); - ClientCode(f2); + ClientCode(*f2); delete f2; return 0; } \ No newline at end of file From 7489c0b11b6e18fb5c2211ad8fb38951eb22918c Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Mon, 16 Sep 2019 11:24:09 -0500 Subject: [PATCH 07/36] Initial commit Factory Method --- src/FactoryMethod/Conceptual/Output.txt | 8 ++ src/FactoryMethod/Conceptual/main.cc | 184 ++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 src/FactoryMethod/Conceptual/Output.txt create mode 100644 src/FactoryMethod/Conceptual/main.cc diff --git a/src/FactoryMethod/Conceptual/Output.txt b/src/FactoryMethod/Conceptual/Output.txt new file mode 100644 index 0000000..b0eab33 --- /dev/null +++ b/src/FactoryMethod/Conceptual/Output.txt @@ -0,0 +1,8 @@ +App: Launched with the ConcreteCreator1. +Client: I'm not aware of the creator's class, but it still works. +Creator: The same creator's code has just worked with {Result of the ConcreteProduct1} + +App: Launched with the ConcreteCreator2. +Client: I'm not aware of the creator's class, but it still works. +Creator: The same creator's code has just worked with {Result of the ConcreteProduct2} + diff --git a/src/FactoryMethod/Conceptual/main.cc b/src/FactoryMethod/Conceptual/main.cc new file mode 100644 index 0000000..ffaa05b --- /dev/null +++ b/src/FactoryMethod/Conceptual/main.cc @@ -0,0 +1,184 @@ +#include +#include + +/** + * EN: Factory Method Design Pattern + * + * Intent: Provides an interface for creating objects in a superclass, but + * allows subclasses to alter the type of objects that will be created. + * + * RU: Паттерн Фабричный Метод + * + * Назначение: Определяет общий интерфейс для создания объектов в суперклассе, + * позволяя подклассам изменять тип создаваемых объектов. + */ + + +/** + * EN: The Product interface declares the operations that all concrete products + * must implement. + * + * RU: Интерфейс Продукта объявляет операции, которые должны выполнять все + * конкретные продукты. + */ + +class Product{ + public: + virtual ~Product(){} + virtual std::string Operation() const =0; +}; + +/** + * EN: Concrete Products provide various implementations of the Product + * interface. + * + * RU: Конкретные Продукты предоставляют различные реализации интерфейса + * Продукта. + */ +class ConcreteProduct1 : public Product{ + + public: + + std::string Operation() const override { + return "{Result of the ConcreteProduct1}"; + } +}; +class ConcreteProduct2 : public Product{ + public: + + std::string Operation() const override { + return "{Result of the ConcreteProduct2}"; + } +}; + + +/** + * EN: The Creator class declares the factory method that is supposed to return + * an object of a Product class. The Creator's subclasses usually provide the + * implementation of this method. + * + * RU: Класс Создатель объявляет фабричный метод, который должен возвращать + * объект класса Продукт. Подклассы Создателя обычно предоставляют реализацию + * этого метода. + */ + +class Creator{ + /** + * EN: Note that the Creator may also provide some default implementation of + * the factory method. + * + * RU: Обратите внимание, что Создатель может также обеспечить реализацию + * фабричного метода по умолчанию. + */ + public: + virtual ~Creator(){}; + virtual Product* FactoryMethod() const=0 ; + /** + * EN: Also note that, despite its name, the Creator's primary + * responsibility is not creating products. Usually, it contains some core + * business logic that relies on Product objects, returned by the factory + * method. Subclasses can indirectly change that business logic by + * overriding the factory method and returning a different type of product + * from it. + * + * RU: Также заметьте, что, несмотря на название, основная обязанность + * Создателя не заключается в создании продуктов. Обычно он содержит + * некоторую базовую бизнес-логику, которая основана на объектах Продуктов, + * возвращаемых фабричным методом. Подклассы могут косвенно изменять эту + * бизнес-логику, переопределяя фабричный метод и возвращая из него другой + * тип продукта. + */ + + std::string SomeOperation() const { + // EN: Call the factory method to create a Product object. + // + // RU: Вызываем фабричный метод, чтобы получить объект-продукт. + Product* product= this->FactoryMethod(); + // EN: Now, use the product. + // + // RU: Далее, работаем с этим продуктом. + std::string result= "Creator: The same creator's code has just worked with "+ product->Operation(); + delete product; + return result; + } +}; + + + + + + +/** + * EN: Concrete Creators override the factory method in order to change the + * resulting product's type. + * + * RU: Конкретные Создатели переопределяют фабричный метод для того, чтобы + * изменить тип результирующего продукта. + */ +class ConcreteCreator1: public Creator{ + /** + * EN: Note that the signature of the method still uses the abstract product + * type, even though the concrete product is actually returned from the + * method. This way the Creator can stay independent of concrete product + * classes. + * + * RU: Обратите внимание, что сигнатура метода по-прежнему использует тип + * абстрактного продукта, хотя фактически из метода возвращается конкретный + * продукт. Таким образом, Создатель может оставаться независимым от + * конкретных классов продуктов. + */ + public: + + Product* FactoryMethod() const override { + return new ConcreteProduct1(); + } +}; + +class ConcreteCreator2: public Creator +{ + public: + + Product* FactoryMethod() const override{ + return new ConcreteProduct2(); + } +}; + +/** + * EN: The client code works with an instance of a concrete creator, albeit + * through its base interface. As long as the client keeps working with the + * creator via the base interface, you can pass it any creator's subclass. + * + * RU: Клиентский код работает с экземпляром конкретного создателя, хотя и через + * его базовый интерфейс. Пока клиент продолжает работать с создателем через + * базовый интерфейс, вы можете передать ему любой подкласс создателя. + */ +void ClientCode(const Creator& creator) +{ + // ... + std::cout << "Client: I'm not aware of the creator's class, but it still works.\n" + << creator.SomeOperation()< Date: Wed, 18 Sep 2019 10:44:01 -0500 Subject: [PATCH 08/36] Builder initial commit --- src/Builder/Conceptual/Output.txt | 9 + src/Builder/Conceptual/main.cc | 271 ++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 src/Builder/Conceptual/Output.txt create mode 100644 src/Builder/Conceptual/main.cc diff --git a/src/Builder/Conceptual/Output.txt b/src/Builder/Conceptual/Output.txt new file mode 100644 index 0000000..43b2aa2 --- /dev/null +++ b/src/Builder/Conceptual/Output.txt @@ -0,0 +1,9 @@ +Standard basic product: +Product parts: PartA1 + +Standard full featured product: +Product parts: PartA1, PartB1, PartC1 + +Custom product: +Product parts: PartA1, PartC1 + diff --git a/src/Builder/Conceptual/main.cc b/src/Builder/Conceptual/main.cc new file mode 100644 index 0000000..4acb2b1 --- /dev/null +++ b/src/Builder/Conceptual/main.cc @@ -0,0 +1,271 @@ +#include +#include +#include + +/** + * EN: Builder Design Pattern + * + * Intent: Lets you construct complex objects step by step. The pattern allows + * you to produce different types and representations of an object using the + * same construction code. + * + * RU: Паттерн Строитель + * + * Назначение: Позволяет создавать сложные объекты пошагово. Строитель даёт + * возможность использовать один и тот же код строительства для получения разных + * представлений объектов. + */ + +/** + * EN: It makes sense to use the Builder pattern only when your products are + * quite complex and require extensive configuration. + * + * Unlike in other creational patterns, different concrete builders can produce + * unrelated products. In other words, results of various builders may not + * always follow the same interface. + * + * RU: Имеет смысл использовать паттерн Строитель только тогда, когда ваши + * продукты достаточно сложны и требуют обширной конфигурации. + * + * В отличие от других порождающих паттернов, различные конкретные строители + * могут производить несвязанные продукты. Другими словами, результаты различных + * строителей могут не всегда следовать одному и тому же интерфейсу. + */ + +class Product1{ + public: + std::vector parts_; + void ListParts()const{ + std::cout << "Product parts: "; + for (size_t i=0;iReset(); + } + + ~ConcreteBuilder1(){ + delete product; + } + + void Reset(){ + this->product= new Product1(); + } + /** + * EN: All production steps work with the same product instance. + * + * RU: Все этапы производства работают с одним и тем же экземпляром + * продукта. + */ + + void ProducePartA()const override{ + this->product->parts_.push_back("PartA1"); + } + + void ProducePartB()const override{ + this->product->parts_.push_back("PartB1"); + } + + void ProducePartC()const override{ + this->product->parts_.push_back("PartC1"); + } + + /** + * EN: Concrete Builders are supposed to provide their own methods for + * retrieving results. That's because various types of builders may create + * entirely different products that don't follow the same interface. + * Therefore, such methods cannot be declared in the base Builder interface + * (at least in a statically typed programming language). Note that PHP is a + * dynamically typed language and this method CAN be in the base interface. + * However, we won't declare it there for the sake of clarity. + * + * Usually, after returning the end result to the client, a builder instance + * is expected to be ready to start producing another product. That's why + * it's a usual practice to call the reset method at the end of the + * `getProduct` method body. However, this behavior is not mandatory, and + * you can make your builders wait for an explicit reset call from the + * client code before disposing of the previous result. + * + * RU: Конкретные Строители должны предоставить свои собственные методы + * получения результатов. Это связано с тем, что различные типы строителей + * могут создавать совершенно разные продукты с разными интерфейсами. + * Поэтому такие методы не могут быть объявлены в базовом интерфейсе + * Строителя (по крайней мере, в статически типизированном языке + * программирования). Обратите внимание, что PHP является динамически + * типизированным языком, и этот метод может быть в базовом интерфейсе. + * Однако мы не будем объявлять его здесь для ясности. + * + * Как правило, после возвращения конечного результата клиенту, экземпляр + * строителя должен быть готов к началу производства следующего продукта. + * Поэтому обычной практикой является вызов метода сброса в конце тела + * метода getProduct. Однако такое поведение не является обязательным, вы + * можете заставить своих строителей ждать явного запроса на сброс из кода + * клиента, прежде чем избавиться от предыдущего результата. + */ + + /** + * EN: Please be careful here with the memory ownership. Once you call GetProduct + * the user of this function is responsable to release this memory. Here could be + * a better option to use smart pointers to avoid memory leaks + * + * RU: + * + */ + + Product1* GetProduct() { + Product1* result= this->product; + this->Reset(); + return result; + } +}; + +/** + * EN: The Director is only responsible for executing the building steps in a + * particular sequence. It is helpful when producing products according to a + * specific order or configuration. Strictly speaking, the Director class is + * optional, since the client can control builders directly. + * + * RU: Директор отвечает только за выполнение шагов построения в определённой + * последовательности. Это полезно при производстве продуктов в определённом + * порядке или особой конфигурации. Строго говоря, класс Директор необязателен, + * так как клиент может напрямую управлять строителями. + */ +class Director{ + /** + * @var Builder + */ + private: + Builder* builder; + /** + * EN: The Director works with any builder instance that the client code + * passes to it. This way, the client code may alter the final type of the + * newly assembled product. + * + * RU: Директор работает с любым экземпляром строителя, который передаётся + * ему клиентским кодом. Таким образом, клиентский код может изменить + * конечный тип вновь собираемого продукта. + */ + + public: + + void set_builder(Builder* builder){ + this->builder=builder; + } + + /** + * EN: The Director can construct several product variations using the same + * building steps. + * + * RU: Директор может строить несколько вариаций продукта, используя + * одинаковые шаги построения. + */ + + void BuildMinimalViableProduct(){ + this->builder->ProducePartA(); + } + + void BuildFullFeaturedProduct(){ + this->builder->ProducePartA(); + this->builder->ProducePartB(); + this->builder->ProducePartC(); + } +}; +/** + * EN: The client code creates a builder object, passes it to the director and + * then initiates the construction process. The end result is retrieved from the + * builder object. + * + * RU: Клиентский код создаёт объект-строитель, передаёт его директору, а затем + * инициирует процесс построения. Конечный результат извлекается из + * объекта-строителя. + */ +/** + * EN: I used raw pointers for simplicity however you may prefer to use smart pointers here + * + * RU: + * + */ +void ClientCode(Director& director) +{ + ConcreteBuilder1* builder = new ConcreteBuilder1(); + director.set_builder(builder); + std::cout << "Standard basic product:\n"; + director.BuildMinimalViableProduct(); + + Product1* p= builder->GetProduct(); + p->ListParts(); + delete p; + + std::cout << "Standard full featured product:\n"; + director.BuildFullFeaturedProduct(); + + p= builder->GetProduct(); + p->ListParts(); + delete p; + + // EN: Remember, the Builder pattern can be used without a Director class. + // + // RU: Помните, что паттерн Строитель можно использовать без класса + // Директор. + std::cout << "Custom product:\n"; + builder->ProducePartA(); + builder->ProducePartC(); + p=builder->GetProduct(); + p->ListParts(); + delete p; + + delete builder; +} + +int main(){ + Director* director= new Director(); + ClientCode(*director); + delete director; + return 0; +} From 5ece8610ae0ea4630f18cf4ea5a60ea33385d40c Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Fri, 20 Sep 2019 10:01:09 -0500 Subject: [PATCH 09/36] Protorypes initial commit --- src/Prototype/Conceptual/Output.txt | 5 + src/Prototype/Conceptual/main.cc | 174 ++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 src/Prototype/Conceptual/Output.txt create mode 100644 src/Prototype/Conceptual/main.cc diff --git a/src/Prototype/Conceptual/Output.txt b/src/Prototype/Conceptual/Output.txt new file mode 100644 index 0000000..a847040 --- /dev/null +++ b/src/Prototype/Conceptual/Output.txt @@ -0,0 +1,5 @@ +Let's create a simple bullet +fire Simple bullet with direction : 90 + +Let's create a Good bullet +fire Good Bullet with direction :10 \ No newline at end of file diff --git a/src/Prototype/Conceptual/main.cc b/src/Prototype/Conceptual/main.cc new file mode 100644 index 0000000..c169595 --- /dev/null +++ b/src/Prototype/Conceptual/main.cc @@ -0,0 +1,174 @@ +#include +#include +#include +#include + +using std::string; + + +// EN: Prototype Design Pattern +// +// Intent: Lets you copy existing objects without making your code dependent on +// their classes. +// +// RU: Паттерн Прототип +// +// Назначение: Позволяет копировать объекты, не вдаваясь в подробности их +// реализации. + + +enum BulletType { + SIMPLE=0, + GOOD +}; + +/** + * EN: The example class that has cloning ability. We'll see how the values of + * field with different types will be cloned. + * + * RU: Пример класса, имеющего возможность клонирования. Мы посмотрим как + * происходит клонирование значений полей разных типов. + */ + + +class Bullet { + +protected: + string bullet_name_; + float speed_; + float fire_power_; + float direction_; + +public: + + Bullet() {} + Bullet(string bullet_name, float speed,float fire_power) + :bullet_name_(bullet_name),speed_(speed),fire_power_(fire_power){ + } + virtual ~Bullet() {} + virtual Bullet* Clone() const = 0; + virtual void Fire(float direction)= 0; +}; + +/** + * EN: Simple Bullet is a Sub-Class of Bullet and implement the Clone Method + * In this example all data members of Bullet Class are in the Stack. If you + * have pointers in your properties for ex: String* name_ ,you will need to + * implement the Copy-Constructor to make sure you have a deep copy from the + * clone method + * + * RU: + */ + +class SimpleBullet: public Bullet { + private: + float damage_power_; +public: + SimpleBullet(string bullet_name, float speed, float fire_power, float damage_power) + :Bullet(bullet_name, speed/2, fire_power),damage_power_(damage_power) { + + } + + /** + * EN: Notice that Clone method return a Pointer to a new Bullet replica. so, the client + * (who call the clone method) has the responsability to free that memory. I you have + * smart pointer knowledge you may prefer to use unique_pointer here. + * + * RU: + */ + Bullet* Clone() const override { + return new SimpleBullet(*this); + } + + void Fire(float direction) override { + this->direction_ = direction; + std::cout << "fire Simple bullet with direction : " << direction<direction_ = direction; + std::cout << "fire Good Bullet with direction :"<< direction< >bullets_; +public: + BulletFactory() { + + bullets_[BulletType::SIMPLE] = new SimpleBullet("Simple Bullet",50.f,75.f,75.f); + bullets_[BulletType::GOOD] = new GoodBullet ("Good Bullet", 60.f, 95.f, 95.f,200.f); + } + + /** + * EN: Be carefull of free all memory allocated. Again, if you have smart pointers knowelege + * will be better to use it here. + * + * RU: + */ + + ~BulletFactory(){ + delete bullets_[BulletType::SIMPLE]; + delete bullets_[BulletType::GOOD]; + } + + /** + * EN: Notice here that you just need to specify the type of the bullet you want and the method + * will create from the object with this type. + * + * RU: + */ + Bullet* CreateBullet(BulletType bulletType) { + return bullets_[bulletType]->Clone(); + } +}; + +void Client(BulletFactory& bullet_factory){ + + std::cout <<"Let's create a simple bullet\n"; + + Bullet* bullet = bullet_factory.CreateBullet(BulletType::SIMPLE); + bullet->Fire(90); + delete bullet; + + std::cout << "\n"; + + std::cout <<"Let's create a Good bullet\n"; + + bullet = bullet_factory.CreateBullet(BulletType::GOOD); + bullet->Fire(10); + + delete bullet; +} + + +int main(){ + BulletFactory* bullet_factory= new BulletFactory(); + Client(*bullet_factory); + delete bullet_factory; + + return 0; +} \ No newline at end of file From 8f6635a67a1f1b2cbac28324750af56cc8297f94 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 2 Oct 2019 10:39:55 -0500 Subject: [PATCH 10/36] fix indentation and move fire method --- src/Prototype/Conceptual/main.cc | 136 ++++++++++++++++--------------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/src/Prototype/Conceptual/main.cc b/src/Prototype/Conceptual/main.cc index c169595..04819c9 100644 --- a/src/Prototype/Conceptual/main.cc +++ b/src/Prototype/Conceptual/main.cc @@ -1,11 +1,9 @@ #include #include #include -#include using std::string; - // EN: Prototype Design Pattern // // Intent: Lets you copy existing objects without making your code dependent on @@ -16,9 +14,9 @@ using std::string; // Назначение: Позволяет копировать объекты, не вдаваясь в подробности их // реализации. - -enum BulletType { - SIMPLE=0, +enum BulletType +{ + SIMPLE = 0, GOOD }; @@ -30,24 +28,27 @@ enum BulletType { * происходит клонирование значений полей разных типов. */ - -class Bullet { +class Bullet +{ protected: string bullet_name_; float speed_; float fire_power_; float direction_; - -public: +public: Bullet() {} - Bullet(string bullet_name, float speed,float fire_power) - :bullet_name_(bullet_name),speed_(speed),fire_power_(fire_power){ + Bullet(string bullet_name, float speed, float fire_power) + : bullet_name_(bullet_name), speed_(speed), fire_power_(fire_power) + { } virtual ~Bullet() {} - virtual Bullet* Clone() const = 0; - virtual void Fire(float direction)= 0; + virtual Bullet *Clone() const = 0; + virtual void Fire(float direction){ + this->direction_ = direction; + std::cout << "fire "<< bullet_name_<<" with direction : " << direction << std::endl; + } }; /** @@ -60,49 +61,44 @@ class Bullet { * RU: */ -class SimpleBullet: public Bullet { - private: - float damage_power_; +class SimpleBullet : public Bullet +{ +private: + float damage_power_; + public: - SimpleBullet(string bullet_name, float speed, float fire_power, float damage_power) - :Bullet(bullet_name, speed/2, fire_power),damage_power_(damage_power) { - + SimpleBullet(string bullet_name, float speed, float fire_power, float damage_power) + : Bullet(bullet_name, speed / 2, fire_power), damage_power_(damage_power) + { } - /** + /** * EN: Notice that Clone method return a Pointer to a new Bullet replica. so, the client * (who call the clone method) has the responsability to free that memory. I you have * smart pointer knowledge you may prefer to use unique_pointer here. * * RU: */ - Bullet* Clone() const override { + Bullet *Clone() const override + { return new SimpleBullet(*this); } - - void Fire(float direction) override { - this->direction_ = direction; - std::cout << "fire Simple bullet with direction : " << direction<direction_ = direction; - std::cout << "fire Good Bullet with direction :"<< direction<> bullets_; -private: - std::unordered_map >bullets_; public: - BulletFactory() { - - bullets_[BulletType::SIMPLE] = new SimpleBullet("Simple Bullet",50.f,75.f,75.f); - bullets_[BulletType::GOOD] = new GoodBullet ("Good Bullet", 60.f, 95.f, 95.f,200.f); + BulletFactory() + { + + bullets_[BulletType::SIMPLE] = new SimpleBullet("Simple Bullet", 50.f, 75.f, 75.f); + bullets_[BulletType::GOOD] = new GoodBullet("Good Bullet", 60.f, 95.f, 95.f, 200.f); } - /** + /** * EN: Be carefull of free all memory allocated. Again, if you have smart pointers knowelege * will be better to use it here. * * RU: */ - ~BulletFactory(){ - delete bullets_[BulletType::SIMPLE]; - delete bullets_[BulletType::GOOD]; - } + ~BulletFactory() + { + delete bullets_[BulletType::SIMPLE]; + delete bullets_[BulletType::GOOD]; + } - /** + /** * EN: Notice here that you just need to specify the type of the bullet you want and the method * will create from the object with this type. * * RU: */ - Bullet* CreateBullet(BulletType bulletType) { + Bullet *CreateBullet(BulletType bulletType) + { return bullets_[bulletType]->Clone(); } }; -void Client(BulletFactory& bullet_factory){ - - std::cout <<"Let's create a simple bullet\n"; - - Bullet* bullet = bullet_factory.CreateBullet(BulletType::SIMPLE); +void Client(BulletFactory &bullet_factory) +{ + + std::cout << "Let's create a simple bullet\n"; + + Bullet *bullet = bullet_factory.CreateBullet(BulletType::SIMPLE); bullet->Fire(90); - delete bullet; + delete bullet; - std::cout << "\n"; + std::cout << "\n"; - std::cout <<"Let's create a Good bullet\n"; + std::cout << "Let's create a Good bullet\n"; bullet = bullet_factory.CreateBullet(BulletType::GOOD); bullet->Fire(10); - delete bullet; + delete bullet; } +int main() +{ + BulletFactory *bullet_factory = new BulletFactory(); + Client(*bullet_factory); + delete bullet_factory; -int main(){ - BulletFactory* bullet_factory= new BulletFactory(); - Client(*bullet_factory); - delete bullet_factory; - - return 0; + return 0; } \ No newline at end of file From 399efc80289426fe713da020ab69067b0d358a75 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 2 Oct 2019 14:21:51 -0500 Subject: [PATCH 11/36] Singleton pattern --- src/Singleton/Conceptual/main.cc | 125 +++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/Singleton/Conceptual/main.cc diff --git a/src/Singleton/Conceptual/main.cc b/src/Singleton/Conceptual/main.cc new file mode 100644 index 0000000..4a38e0e --- /dev/null +++ b/src/Singleton/Conceptual/main.cc @@ -0,0 +1,125 @@ +#include + +/** + * EN: Singleton Design Pattern + * + * Intent: Lets you ensure that a class has only one instance, while providing a + * global access point to this instance. + * + * RU: Паттерн Одиночка + * + * Назначение: Гарантирует, что у класса есть только один экземпляр, и + * предоставляет к нему глобальную точку доступа. + */ +/** + * EN: The Singleton class defines the `GetInstance` method that serves as an + * alternative to constructor and lets clients access the same instance of this + * class over and over. + * + * RU: Класс Одиночка предоставляет метод `GetInstance`, который ведёт себя как + * альтернативный конструктор и позволяет клиентам получать один и тот же + * экземпляр класса при каждом вызове. + */ +class Singleton +{ + + /** + * EN: The Singleton's constructor should always be private to prevent + * direct construction calls with the `new` operator. + * + * RU: Конструктор Одиночки всегда должен быть скрытым, чтобы предотвратить + * создание объекта через оператор new. + */ + +protected: + Singleton() + { + } + +public: + /** + * EN: Singletons should not be cloneable. + * + * RU: Одиночки не должны быть клонируемыми. + */ + Singleton(Singleton &other) = delete; + /** + * EN: Singletons should not be assignable. + * + * RU: + */ + void operator=(const Singleton &) = delete; + /** + * EN: This is the static method that controls the access to the singleton + * instance. On the first run, it creates a singleton object and places it + * into the static field. On subsequent runs, it returns the client existing + * object stored in the static field. + * + * This implementation lets you subclass the Singleton class while keeping + * just one instance of each subclass around. + * + * RU: Это статический метод, управляющий доступом к экземпляру одиночки. + * При первом запуске, он создаёт экземпляр одиночки и помещает его в + * статическое поле. При последующих запусках, он возвращает клиенту объект, + * хранящийся в статическом поле. + * + * Эта реализация позволяет вам расширять класс Одиночки, сохраняя повсюду + * только один экземпляр каждого подкласса. + */ + + static Singleton *getInstance(); + /** + * EN: Finally, any singleton should define some business logic, which can + * be executed on its instance. + * + * RU: Наконец, любой одиночка должен содержать некоторую бизнес-логику, + * которая может быть выполнена на его экземпляре. + */ + void someBusinessLogic() + { + // ... + } +}; + +/** + * EN: Static methods should be defined outside the class. + * + * RU: + */ +Singleton *Singleton::getInstance() +{ + /** + * EN: This is a safer way to create an instance. instance = new Singleton is dangeruous + * in case two instance threads wants to access at the same time + * + * RU: + */ + static Singleton singleton; + return &singleton; +} + +/** + * EN: The client code. + * + * RU: Клиентский код. + */ +void ClientCode() +{ + Singleton *s1 = Singleton::getInstance(); + Singleton *s2 = Singleton::getInstance(); + if (s1 == s2) + { + std::cout << "Singleton works, both variables contain the same instance.\n"; + } + else + { + std::cout << "Singleton failed, variables contain different instances.\n"; + } + delete s1; +} + +int main() +{ + ClientCode(); + return 0; +} \ No newline at end of file From b605458396cc2f3e26c103d7f83f6e032a5e4554 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 2 Oct 2019 14:23:13 -0500 Subject: [PATCH 12/36] out --- src/Singleton/Conceptual/Output.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/Singleton/Conceptual/Output.txt diff --git a/src/Singleton/Conceptual/Output.txt b/src/Singleton/Conceptual/Output.txt new file mode 100644 index 0000000..6bcc570 --- /dev/null +++ b/src/Singleton/Conceptual/Output.txt @@ -0,0 +1 @@ +Singleton works, both variables contain the same instance. \ No newline at end of file From 465bf1a2991a9b1537c9dd5543dec1edf0df7bf7 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 2 Oct 2019 14:25:42 -0500 Subject: [PATCH 13/36] name syntax --- src/Singleton/Conceptual/main.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Singleton/Conceptual/main.cc b/src/Singleton/Conceptual/main.cc index 4a38e0e..1f32b73 100644 --- a/src/Singleton/Conceptual/main.cc +++ b/src/Singleton/Conceptual/main.cc @@ -67,7 +67,7 @@ class Singleton * только один экземпляр каждого подкласса. */ - static Singleton *getInstance(); + static Singleton *GetInstance(); /** * EN: Finally, any singleton should define some business logic, which can * be executed on its instance. @@ -75,7 +75,7 @@ class Singleton * RU: Наконец, любой одиночка должен содержать некоторую бизнес-логику, * которая может быть выполнена на его экземпляре. */ - void someBusinessLogic() + void SomeBusinessLogic() { // ... } @@ -86,7 +86,7 @@ class Singleton * * RU: */ -Singleton *Singleton::getInstance() +Singleton *Singleton::GetInstance() { /** * EN: This is a safer way to create an instance. instance = new Singleton is dangeruous @@ -105,8 +105,8 @@ Singleton *Singleton::getInstance() */ void ClientCode() { - Singleton *s1 = Singleton::getInstance(); - Singleton *s2 = Singleton::getInstance(); + Singleton *s1 = Singleton::GetInstance(); + Singleton *s2 = Singleton::GetInstance(); if (s1 == s2) { std::cout << "Singleton works, both variables contain the same instance.\n"; From 93435d916dd312d9438691b0acbe7a49b3bd4433 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Thu, 3 Oct 2019 17:06:13 -0500 Subject: [PATCH 14/36] Prototype names change --- src/Prototype/Conceptual/main.cc | 69 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/Prototype/Conceptual/main.cc b/src/Prototype/Conceptual/main.cc index 04819c9..e8a3ebe 100644 --- a/src/Prototype/Conceptual/main.cc +++ b/src/Prototype/Conceptual/main.cc @@ -14,7 +14,7 @@ using std::string; // Назначение: Позволяет копировать объекты, не вдаваясь в подробности их // реализации. -enum BulletType +enum Type { SIMPLE = 0, GOOD @@ -28,8 +28,7 @@ enum BulletType * происходит клонирование значений полей разных типов. */ -class Bullet -{ +class Prototype{ protected: string bullet_name_; @@ -38,13 +37,13 @@ class Bullet float direction_; public: - Bullet() {} - Bullet(string bullet_name, float speed, float fire_power) + Prototype() {} + Prototype(string bullet_name, float speed, float fire_power) : bullet_name_(bullet_name), speed_(speed), fire_power_(fire_power) { } - virtual ~Bullet() {} - virtual Bullet *Clone() const = 0; + virtual ~Prototype() {} + virtual Prototype *Clone() const = 0; virtual void Fire(float direction){ this->direction_ = direction; std::cout << "fire "<< bullet_name_<<" with direction : " << direction << std::endl; @@ -61,14 +60,14 @@ class Bullet * RU: */ -class SimpleBullet : public Bullet +class ConcretePrototype1 : public Prototype { private: float damage_power_; public: - SimpleBullet(string bullet_name, float speed, float fire_power, float damage_power) - : Bullet(bullet_name, speed / 2, fire_power), damage_power_(damage_power) + ConcretePrototype1(string bullet_name, float speed, float fire_power, float damage_power) + : Prototype(bullet_name, speed / 2, fire_power), damage_power_(damage_power) { } @@ -79,25 +78,25 @@ class SimpleBullet : public Bullet * * RU: */ - Bullet *Clone() const override + Prototype *Clone() const override { - return new SimpleBullet(*this); + return new ConcretePrototype1(*this); } }; -class GoodBullet : public Bullet +class ConcretePrototype2 : public Prototype { private: float damage_area_; public: - GoodBullet(string bullet_name, float speed, float fire_power, float damage_power, float damage_area) - : Bullet(bullet_name, speed, fire_power), damage_area_(damage_area) + ConcretePrototype2(string bullet_name, float speed, float fire_power, float damage_power, float damage_area) + : Prototype(bullet_name, speed, fire_power), damage_area_(damage_area) { } - Bullet *Clone() const override + Prototype *Clone() const override { - return new GoodBullet(*this); + return new ConcretePrototype2(*this); } }; @@ -108,18 +107,18 @@ class GoodBullet : public Bullet * RU: */ -class BulletFactory +class PrototypeFactory { private: - std::unordered_map> bullets_; + std::unordered_map> bullets_; public: - BulletFactory() + PrototypeFactory() { - bullets_[BulletType::SIMPLE] = new SimpleBullet("Simple Bullet", 50.f, 75.f, 75.f); - bullets_[BulletType::GOOD] = new GoodBullet("Good Bullet", 60.f, 95.f, 95.f, 200.f); + bullets_[Type::SIMPLE] = new ConcretePrototype1("Simple Bullet", 50.f, 75.f, 75.f); + bullets_[Type::GOOD] = new ConcretePrototype2("Good Bullet", 60.f, 95.f, 95.f, 200.f); } /** @@ -129,10 +128,10 @@ class BulletFactory * RU: */ - ~BulletFactory() + ~PrototypeFactory() { - delete bullets_[BulletType::SIMPLE]; - delete bullets_[BulletType::GOOD]; + delete bullets_[Type::SIMPLE]; + delete bullets_[Type::GOOD]; } /** @@ -141,34 +140,34 @@ class BulletFactory * * RU: */ - Bullet *CreateBullet(BulletType bulletType) + Prototype *CreateBullet(Type Type) { - return bullets_[bulletType]->Clone(); + return bullets_[Type]->Clone(); } }; -void Client(BulletFactory &bullet_factory) +void Client(PrototypeFactory &bullet_factory) { std::cout << "Let's create a simple bullet\n"; - Bullet *bullet = bullet_factory.CreateBullet(BulletType::SIMPLE); - bullet->Fire(90); - delete bullet; + Prototype *prototype = bullet_factory.CreateBullet(Type::SIMPLE); + prototype->Fire(90); + delete prototype; std::cout << "\n"; std::cout << "Let's create a Good bullet\n"; - bullet = bullet_factory.CreateBullet(BulletType::GOOD); - bullet->Fire(10); + prototype = bullet_factory.CreateBullet(Type::GOOD); + prototype->Fire(10); - delete bullet; + delete prototype; } int main() { - BulletFactory *bullet_factory = new BulletFactory(); + PrototypeFactory *bullet_factory = new PrototypeFactory(); Client(*bullet_factory); delete bullet_factory; From d0ce78d9db6a5f97a704738a1f30373e5f314097 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Thu, 3 Oct 2019 17:10:07 -0500 Subject: [PATCH 15/36] Thread - NonThread Singleton --- .../Conceptual/NonThreadSafe/Output.txt | 1 + .../Conceptual/NonThreadSafe/main.cc | 120 +++++++++++++++ .../Conceptual/ThreadSafe/Output.txt | 1 + src/Singleton/Conceptual/ThreadSafe/main.cc | 144 ++++++++++++++++++ 4 files changed, 266 insertions(+) create mode 100644 src/Singleton/Conceptual/NonThreadSafe/Output.txt create mode 100644 src/Singleton/Conceptual/NonThreadSafe/main.cc create mode 100644 src/Singleton/Conceptual/ThreadSafe/Output.txt create mode 100644 src/Singleton/Conceptual/ThreadSafe/main.cc diff --git a/src/Singleton/Conceptual/NonThreadSafe/Output.txt b/src/Singleton/Conceptual/NonThreadSafe/Output.txt new file mode 100644 index 0000000..6bcc570 --- /dev/null +++ b/src/Singleton/Conceptual/NonThreadSafe/Output.txt @@ -0,0 +1 @@ +Singleton works, both variables contain the same instance. \ No newline at end of file diff --git a/src/Singleton/Conceptual/NonThreadSafe/main.cc b/src/Singleton/Conceptual/NonThreadSafe/main.cc new file mode 100644 index 0000000..2334d7f --- /dev/null +++ b/src/Singleton/Conceptual/NonThreadSafe/main.cc @@ -0,0 +1,120 @@ +#include + +/** + * EN: Singleton Design Pattern + * + * Intent: Lets you ensure that a class has only one instance, while providing a + * global access point to this instance. + * + * RU: Паттерн Одиночка + * + * Назначение: Гарантирует, что у класса есть только один экземпляр, и + * предоставляет к нему глобальную точку доступа. + */ +/** + * EN: The Singleton class defines the `GetInstance` method that serves as an + * alternative to constructor and lets clients access the same instance of this + * class over and over. + * + * RU: Класс Одиночка предоставляет метод `GetInstance`, который ведёт себя как + * альтернативный конструктор и позволяет клиентам получать один и тот же + * экземпляр класса при каждом вызове. + */ +class Singleton +{ + + /** + * EN: The Singleton's constructor should always be private to prevent + * direct construction calls with the `new` operator. + * + * RU: Конструктор Одиночки всегда должен быть скрытым, чтобы предотвратить + * создание объекта через оператор new. + */ + +protected: + Singleton() + { + } + +public: + /** + * EN: Singletons should not be cloneable. + * + * RU: Одиночки не должны быть клонируемыми. + */ + Singleton(Singleton &other) = delete; + /** + * EN: Singletons should not be assignable. + * + * RU: + */ + void operator=(const Singleton &) = delete; + /** + * EN: This is the static method that controls the access to the singleton + * instance. On the first run, it creates a singleton object and places it + * into the static field. On subsequent runs, it returns the client existing + * object stored in the static field. + * + * + * RU: Это статический метод, управляющий доступом к экземпляру одиночки. + * При первом запуске, он создаёт экземпляр одиночки и помещает его в + * статическое поле. При последующих запусках, он возвращает клиенту объект, + * хранящийся в статическом поле. + * + */ + + static Singleton *GetInstance(); + /** + * EN: Finally, any singleton should define some business logic, which can + * be executed on its instance. + * + * RU: Наконец, любой одиночка должен содержать некоторую бизнес-логику, + * которая может быть выполнена на его экземпляре. + */ + void SomeBusinessLogic() + { + // ... + } +}; + +/** + * EN: Static methods should be defined outside the class. + * + * RU: + */ +Singleton *Singleton::GetInstance() +{ + /** + * EN: This is a safer way to create an instance. instance = new Singleton is dangeruous + * in case two instance threads wants to access at the same time + * + * RU: + */ + static Singleton singleton; + return &singleton; +} + +/** + * EN: The client code. + * + * RU: Клиентский код. + */ +void ClientCode() +{ + Singleton *s1 = Singleton::GetInstance(); + Singleton *s2 = Singleton::GetInstance(); + if (s1 == s2) + { + std::cout << "Singleton works, both variables contain the same instance.\n"; + } + else + { + std::cout << "Singleton failed, variables contain different instances.\n"; + } +} + +int main() +{ + ClientCode(); + return 0; +} \ No newline at end of file diff --git a/src/Singleton/Conceptual/ThreadSafe/Output.txt b/src/Singleton/Conceptual/ThreadSafe/Output.txt new file mode 100644 index 0000000..6bcc570 --- /dev/null +++ b/src/Singleton/Conceptual/ThreadSafe/Output.txt @@ -0,0 +1 @@ +Singleton works, both variables contain the same instance. \ No newline at end of file diff --git a/src/Singleton/Conceptual/ThreadSafe/main.cc b/src/Singleton/Conceptual/ThreadSafe/main.cc new file mode 100644 index 0000000..d9ca46d --- /dev/null +++ b/src/Singleton/Conceptual/ThreadSafe/main.cc @@ -0,0 +1,144 @@ +/** + * EN: Have in mind it is an ilustrative trivial example, in real world + * you may have in mind some more possible issues. + * + * RU: + */ + +#include +#include +#include + +/** + * EN: Singleton Design Pattern + * + * Intent: Lets you ensure that a class has only one instance, while providing a + * global access point to this instance. + * + * RU: Паттерн Одиночка + * + * Назначение: Гарантирует, что у класса есть только один экземпляр, и + * предоставляет к нему глобальную точку доступа. + */ +/** + * EN: The Singleton class defines the `GetInstance` method that serves as an + * alternative to constructor and lets clients access the same instance of this + * class over and over. + * + * RU: Класс Одиночка предоставляет метод `GetInstance`, который ведёт себя как + * альтернативный конструктор и позволяет клиентам получать один и тот же + * экземпляр класса при каждом вызове. + */ +class Singleton +{ + + /** + * EN: The Singleton's constructor/destructor should always be private to prevent + * direct construction/desctruction calls with the `new`/`delete` operator. + * + * RU: Конструктор Одиночки всегда должен быть скрытым, чтобы предотвратить + * создание объекта через оператор new. + */ +private: + static std::atomic pinstance; + static std::mutex mutex_; + +protected: + Singleton() + { + } + ~Singleton() {} + +public: + /** + * EN: Singletons should not be cloneable. + * + * RU: Одиночки не должны быть клонируемыми. + */ + Singleton(Singleton &other) = delete; + /** + * EN: Singletons should not be assignable. + * + * RU: + */ + void operator=(const Singleton &) = delete; + /** + * EN: This is the static method that controls the access to the singleton + * instance. On the first run, it creates a singleton object and places it + * into the static field. On subsequent runs, it returns the client existing + * object stored in the static field. + * + * + * RU: Это статический метод, управляющий доступом к экземпляру одиночки. + * При первом запуске, он создаёт экземпляр одиночки и помещает его в + * статическое поле. При последующих запусках, он возвращает клиенту объект, + * хранящийся в статическом поле. + * + */ + + static Singleton *GetInstance(); + /** + * EN: Finally, any singleton should define some business logic, which can + * be executed on its instance. + * + * RU: Наконец, любой одиночка должен содержать некоторую бизнес-логику, + * которая может быть выполнена на его экземпляре. + */ + void SomeBusinessLogic() + { + // ... + } +}; + +/** + * EN: Static methods should be defined outside the class. + * + * RU: + */ + +std::atomic Singleton::pinstance{nullptr}; +std::mutex Singleton::mutex_; + +/** + * EN: The first time we call GetInstance we will lock the storage location + * and then we make sure again that the variable is null and then we + * set the value. + * RU: + */ +Singleton *Singleton::GetInstance() +{ + if (pinstance == nullptr) + { + std::lock_guard lock(mutex_); + if (pinstance == nullptr) + { + pinstance = new Singleton; + } + } + return pinstance; +} + +/** + * EN: The client code. + * + * RU: Клиентский код. + */ +void ClientCode() +{ + Singleton *s1 = Singleton::GetInstance(); + Singleton *s2 = Singleton::GetInstance(); + if (s1 == s2) + { + std::cout << "Singleton works, both variables contain the same instance.\n"; + } + else + { + std::cout << "Singleton failed, variables contain different instances.\n"; + } +} + +int main() +{ + ClientCode(); + return 0; +} \ No newline at end of file From 8fa92c6905b13508dba19a137551e8aac42ed1bf Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Fri, 4 Oct 2019 10:16:36 -0500 Subject: [PATCH 16/36] Adapter Example --- src/Adapter/Conceptual/Output.txt | 8 +++ src/Adapter/Conceptual/main.cc | 101 ++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/Adapter/Conceptual/Output.txt create mode 100644 src/Adapter/Conceptual/main.cc diff --git a/src/Adapter/Conceptual/Output.txt b/src/Adapter/Conceptual/Output.txt new file mode 100644 index 0000000..59d5d28 --- /dev/null +++ b/src/Adapter/Conceptual/Output.txt @@ -0,0 +1,8 @@ +Client: I can work just fine with the Target objects: +Target: The default target's behavior. + +Client: The Adaptee class has a weird interface. See, I don't understand it: +Adaptee: .eetpadA eht fo roivaheb laicepS + +Client: But I can work with it via the Adapter: +Adapter: (TRANSLATED) Special behavior of the Adaptee. diff --git a/src/Adapter/Conceptual/main.cc b/src/Adapter/Conceptual/main.cc new file mode 100644 index 0000000..bb152b4 --- /dev/null +++ b/src/Adapter/Conceptual/main.cc @@ -0,0 +1,101 @@ +#include +#include +#include +/** + * EN: Adapter Design Pattern + * + * Intent: Provides a unified interface that allows objects with incompatible + * interfaces to collaborate. + * + * RU: Паттерн Адаптер + * + * Назначение: Позволяет объектам с несовместимыми интерфейсами работать вместе. + */ +/** + * EN: The Target defines the domain-specific interface used by the client code. + * + * RU: Целевой класс объявляет интерфейс, с которым может работать клиентский + * код. + */ +class Target +{ +public: + virtual ~Target() = default; + + virtual std::string Request() const + { + return "Target: The default target's behavior."; + } +}; +/** + * EN: The Adaptee contains some useful behavior, but its interface is + * incompatible with the existing client code. The Adaptee needs some adaptation + * before the client code can use it. + * + * RU: Адаптируемый класс содержит некоторое полезное поведение, но его + * интерфейс несовместим с существующим клиентским кодом. Адаптируемый класс + * нуждается в некоторой доработке, прежде чем клиентский код сможет его + * использовать. + */ +class Adaptee +{ +public: + std::string SpecificRequest() const + { + return ".eetpadA eht fo roivaheb laicepS"; + } +}; +/** + * EN: The Adapter makes the Adaptee's interface compatible with the Target's + * interface. + * + * RU: Адаптер делает интерфейс Адаптируемого класса совместимым с целевым + * интерфейсом. + */ +class Adapter : public Target +{ +private: + Adaptee *adaptee_; + +public: + Adapter(Adaptee *adaptee) : adaptee_(adaptee) + { + } + std::string Request() const override + { + std::string to_reverse = this->adaptee_->SpecificRequest(); + std::reverse(to_reverse.begin(), to_reverse.end()); + return "Adapter: (TRANSLATED) " + to_reverse; + } +}; +/** + * EN: The client code supports all classes that follow the Target interface. + * + * RU: Клиентский код поддерживает все классы, использующие целевой интерфейс. + */ +void ClientCode(const Target *target) +{ + std::cout << target->Request(); +} + +int main() +{ + std::cout << "Client: I can work just fine with the Target objects:\n"; + Target *target = new Target; + ClientCode(target); + std::cout << "\n\n"; + Adaptee *adaptee = new Adaptee; + std::cout << "Client: The Adaptee class has a weird interface. See, I don't understand it:\n"; + std::cout << "Adaptee: " << adaptee->SpecificRequest(); + std::cout << "\n\n"; + std::cout << "Client: But I can work with it via the Adapter:\n"; + Adapter *adapter = new Adapter(adaptee); + ClientCode(adapter); + std::cout << "\n"; + + delete target; + delete adaptee; + delete adapter; + + return 0; +} From a5ac74aabd6521c28c04ad942240bffaf16491aa Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Fri, 4 Oct 2019 12:12:08 -0500 Subject: [PATCH 17/36] delete atomic --- src/Singleton/Conceptual/ThreadSafe/main.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Singleton/Conceptual/ThreadSafe/main.cc b/src/Singleton/Conceptual/ThreadSafe/main.cc index d9ca46d..fa9d10d 100644 --- a/src/Singleton/Conceptual/ThreadSafe/main.cc +++ b/src/Singleton/Conceptual/ThreadSafe/main.cc @@ -6,7 +6,6 @@ */ #include -#include #include /** @@ -40,7 +39,7 @@ class Singleton * создание объекта через оператор new. */ private: - static std::atomic pinstance; + static Singleton * pinstance; static std::mutex mutex_; protected: @@ -96,7 +95,7 @@ class Singleton * RU: */ -std::atomic Singleton::pinstance{nullptr}; +Singleton* Singleton::pinstance{nullptr}; std::mutex Singleton::mutex_; /** From 7004f58e48c460ad145ab2da2d0824c69255fc64 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Mon, 7 Oct 2019 11:12:12 -0500 Subject: [PATCH 18/36] Bridge Pattern --- src/Bridge/Conceptual/Output.txt | 7 ++ src/Bridge/Conceptual/main.cc | 171 +++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/Bridge/Conceptual/Output.txt create mode 100644 src/Bridge/Conceptual/main.cc diff --git a/src/Bridge/Conceptual/Output.txt b/src/Bridge/Conceptual/Output.txt new file mode 100644 index 0000000..0030a4c --- /dev/null +++ b/src/Bridge/Conceptual/Output.txt @@ -0,0 +1,7 @@ +Abstraction: Base operation with: +ConcreteImplementationA: Here's the result on the platform A. + +ExtendedAbstraction: Extended operation with: +ConcreteImplementationB: Here's the result on the platform B. + + diff --git a/src/Bridge/Conceptual/main.cc b/src/Bridge/Conceptual/main.cc new file mode 100644 index 0000000..5456d0a --- /dev/null +++ b/src/Bridge/Conceptual/main.cc @@ -0,0 +1,171 @@ +#include +#include + +/** + * EN: Bridge Design Pattern + * + * Intent: Lets you split a large class or a set of closely related classes into + * two separate hierarchies—abstraction and implementation—which can be + * developed independently of each other. + * + * A + * / \ A N + * Aa Ab ===> / \ / \ + * / \ / \ Aa(N) Ab(N) 1 2 + * Aa1 Aa2 Ab1 Ab2 + * + * RU: Паттерн Мост + * + * Назначение: Разделяет один или несколько классов на две отдельные иерархии — + * абстракцию и реализацию, позволяя изменять их независимо друг от друга. + * + * A + * / \ A N + * Aa Ab ===> / \ / \ + * / \ / \ Aa(N) Ab(N) 1 2 + * Aa1 Aa2 Ab1 Ab2 + */ + + +/** + * EN: The Implementation defines the interface for all implementation classes. + * It doesn't have to match the Abstraction's interface. In fact, the two + * interfaces can be entirely different. Typically the Implementation interface + * provides only primitive operations, while the Abstraction defines higher- + * level operations based on those primitives. + * + * RU: Реализация устанавливает интерфейс для всех классов реализации. Он не + * должен соответствовать интерфейсу Абстракции. На практике оба интерфейса + * могут быть совершенно разными. Как правило, интерфейс Реализации + * предоставляет только примитивные операции, в то время как Абстракция + * определяет операции более высокого уровня, основанные на этих примитивах. + */ + +class Implementation +{ + public: + virtual ~Implementation(){} + virtual std::string OperationImplementation() const =0 ; +}; + + +/** + * EN: Each Concrete Implementation corresponds to a specific platform and + * implements the Implementation interface using that platform's API. + * + * RU: Каждая Конкретная Реализация соответствует определённой платформе и + * реализует интерфейс Реализации с использованием API этой платформы. + */ +class ConcreteImplementationA: public Implementation +{ + public: + std::string OperationImplementation()const override + { + return "ConcreteImplementationA: Here's the result on the platform A.\n"; + } +}; +class ConcreteImplementationB: public Implementation +{ + public: + std::string OperationImplementation()const override + { + return "ConcreteImplementationB: Here's the result on the platform B.\n"; + } +}; + +/** + * EN: The Abstraction defines the interface for the "control" part of the two + * class hierarchies. It maintains a reference to an object of the + * Implementation hierarchy and delegates all of the real work to this object. + * + * RU: Абстракция устанавливает интерфейс для «управляющей» части двух иерархий + * классов. Она содержит ссылку на объект из иерархии Реализации и делегирует + * ему всю настоящую работу. + */ + +class Abstraction{ + /** + * @var Implementation + */ + protected: + Implementation* implementation_; + + public: + + Abstraction(Implementation* implementation):implementation_(implementation){ + } + + virtual ~Abstraction(){ + + } + + virtual std::string Operation() const{ + return "Abstraction: Base operation with:\n" + + this->implementation_->OperationImplementation(); + } +}; +/** + * EN: You can extend the Abstraction without changing the Implementation + * classes. + * + * RU: Можно расширить Абстракцию без изменения классов Реализации. + */ +class ExtendedAbstraction : public Abstraction +{ + public: + + ExtendedAbstraction(Implementation* implementation): Abstraction(implementation){ + + } + std::string Operation() const override + { + return "ExtendedAbstraction: Extended operation with:\n" + + this->implementation_->OperationImplementation(); + } +}; + + +/** + * EN: Except for the initialization phase, where an Abstraction object gets + * linked with a specific Implementation object, the client code should only + * depend on the Abstraction class. This way the client code can support any + * abstraction-implementation combination. + * + * RU: За исключением этапа инициализации, когда объект Абстракции связывается с + * определённым объектом Реализации, клиентский код должен зависеть только от + * класса Абстракции. Таким образом, клиентский код может поддерживать любую + * комбинацию абстракции и реализации. + */ +void ClientCode(const Abstraction& abstraction) +{ + // ... + std::cout << abstraction.Operation(); + // ... +} +/** + * EN: The client code should be able to work with any pre-configured + * abstraction-implementation combination. + * + * RU: Клиентский код должен работать с любой предварительно сконфигурированной + * комбинацией абстракции и реализации. + */ + +int main(){ + + Implementation* implementation = new ConcreteImplementationA; + Abstraction* abstraction = new Abstraction(implementation); + ClientCode(*abstraction); + std::cout << std::endl; + delete implementation; + delete abstraction; + + implementation = new ConcreteImplementationB; + abstraction = new ExtendedAbstraction(implementation); + ClientCode(*abstraction); + + delete implementation; + delete abstraction; + + return 0; +} + From 655e7641450966343562b5be2926ef4ac7c7e9f1 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 9 Oct 2019 10:41:00 -0500 Subject: [PATCH 19/36] delete unused files and add prototypes pattern --- src/Prototype/Conceptual/Output.txt | 8 +- src/Prototype/Conceptual/main.cc | 79 +++++++++--------- src/Singleton/Conceptual/Output.txt | 1 - src/Singleton/Conceptual/main.cc | 125 ---------------------------- 4 files changed, 43 insertions(+), 170 deletions(-) delete mode 100644 src/Singleton/Conceptual/Output.txt delete mode 100644 src/Singleton/Conceptual/main.cc diff --git a/src/Prototype/Conceptual/Output.txt b/src/Prototype/Conceptual/Output.txt index a847040..998bf68 100644 --- a/src/Prototype/Conceptual/Output.txt +++ b/src/Prototype/Conceptual/Output.txt @@ -1,5 +1,5 @@ -Let's create a simple bullet -fire Simple bullet with direction : 90 +Let's create a Prototype 1 +Call Method from PROTOTYPE_1 with field : 90 -Let's create a Good bullet -fire Good Bullet with direction :10 \ No newline at end of file +Let's create a Prototype 2 +Call Method from PROTOTYPE_2 with field : 10 \ No newline at end of file diff --git a/src/Prototype/Conceptual/main.cc b/src/Prototype/Conceptual/main.cc index e8a3ebe..f39f300 100644 --- a/src/Prototype/Conceptual/main.cc +++ b/src/Prototype/Conceptual/main.cc @@ -16,8 +16,8 @@ using std::string; enum Type { - SIMPLE = 0, - GOOD + PROTOTYPE_1 = 0, + PROTOTYPE_2 }; /** @@ -31,28 +31,26 @@ enum Type class Prototype{ protected: - string bullet_name_; - float speed_; - float fire_power_; - float direction_; + string prototype_name_; + float prototype_field_; public: Prototype() {} - Prototype(string bullet_name, float speed, float fire_power) - : bullet_name_(bullet_name), speed_(speed), fire_power_(fire_power) + Prototype(string prototype_name) + : prototype_name_(prototype_name) { } virtual ~Prototype() {} virtual Prototype *Clone() const = 0; - virtual void Fire(float direction){ - this->direction_ = direction; - std::cout << "fire "<< bullet_name_<<" with direction : " << direction << std::endl; + virtual void Method(float prototype_field){ + this->prototype_field_ = prototype_field; + std::cout << "Call Method from "<< prototype_name_<<" with field : " << prototype_field << std::endl; } }; /** - * EN: Simple Bullet is a Sub-Class of Bullet and implement the Clone Method - * In this example all data members of Bullet Class are in the Stack. If you + * EN: ConcretePrototype1 is a Sub-Class of Prototype and implement the Clone Method + * In this example all data members of Prototype Class are in the Stack. If you * have pointers in your properties for ex: String* name_ ,you will need to * implement the Copy-Constructor to make sure you have a deep copy from the * clone method @@ -63,16 +61,16 @@ class Prototype{ class ConcretePrototype1 : public Prototype { private: - float damage_power_; + float concrete_prototype_field1_; public: - ConcretePrototype1(string bullet_name, float speed, float fire_power, float damage_power) - : Prototype(bullet_name, speed / 2, fire_power), damage_power_(damage_power) + ConcretePrototype1(string prototype_name, float concrete_prototype_field) + : Prototype(prototype_name), concrete_prototype_field1_(concrete_prototype_field) { } /** - * EN: Notice that Clone method return a Pointer to a new Bullet replica. so, the client + * EN: Notice that Clone method return a Pointer to a new ConcretePrototype1 replica. so, the client * (who call the clone method) has the responsability to free that memory. I you have * smart pointer knowledge you may prefer to use unique_pointer here. * @@ -87,11 +85,11 @@ class ConcretePrototype1 : public Prototype class ConcretePrototype2 : public Prototype { private: - float damage_area_; + float concrete_prototype_field2_; public: - ConcretePrototype2(string bullet_name, float speed, float fire_power, float damage_power, float damage_area) - : Prototype(bullet_name, speed, fire_power), damage_area_(damage_area) + ConcretePrototype2(string prototype_name, float concrete_prototype_field) + : Prototype(prototype_name), concrete_prototype_field2_(concrete_prototype_field) { } Prototype *Clone() const override @@ -101,8 +99,9 @@ class ConcretePrototype2 : public Prototype }; /** - * EN: In Bullet Factory you have two protorypes of each bullet, so each time - * you want to create a bullet , you can use the existing ones and clone those. + * EN: In PrototypeFactory you have two concrete prototypes, one for each concrete + * prototype class, so each time you want to create a bullet , + * you can use the existing ones and clone those. * * RU: */ @@ -111,14 +110,14 @@ class PrototypeFactory { private: - std::unordered_map> bullets_; + std::unordered_map> prototypes_; public: PrototypeFactory() { - bullets_[Type::SIMPLE] = new ConcretePrototype1("Simple Bullet", 50.f, 75.f, 75.f); - bullets_[Type::GOOD] = new ConcretePrototype2("Good Bullet", 60.f, 95.f, 95.f, 200.f); + prototypes_[Type::PROTOTYPE_1] = new ConcretePrototype1("PROTOTYPE_1 ", 50.f); + prototypes_[Type::PROTOTYPE_2] = new ConcretePrototype2("PROTOTYPE_2 ", 60.f); } /** @@ -130,46 +129,46 @@ class PrototypeFactory ~PrototypeFactory() { - delete bullets_[Type::SIMPLE]; - delete bullets_[Type::GOOD]; + delete prototypes_[Type::PROTOTYPE_1]; + delete prototypes_[Type::PROTOTYPE_2]; } /** - * EN: Notice here that you just need to specify the type of the bullet you want and the method + * EN: Notice here that you just need to specify the type of the prototype you want and the method * will create from the object with this type. * * RU: */ - Prototype *CreateBullet(Type Type) + Prototype *CreatePrototype(Type type) { - return bullets_[Type]->Clone(); + return prototypes_[type]->Clone(); } }; -void Client(PrototypeFactory &bullet_factory) +void Client(PrototypeFactory &prototype_factory) { - std::cout << "Let's create a simple bullet\n"; + std::cout << "Let's create a Prototype 1\n"; - Prototype *prototype = bullet_factory.CreateBullet(Type::SIMPLE); - prototype->Fire(90); + Prototype *prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_1); + prototype->Method(90); delete prototype; std::cout << "\n"; - std::cout << "Let's create a Good bullet\n"; + std::cout << "Let's create a Prototype 2 \n"; - prototype = bullet_factory.CreateBullet(Type::GOOD); - prototype->Fire(10); + prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_2); + prototype->Method(10); delete prototype; } int main() { - PrototypeFactory *bullet_factory = new PrototypeFactory(); - Client(*bullet_factory); - delete bullet_factory; + PrototypeFactory *prototype_factory = new PrototypeFactory(); + Client(*prototype_factory); + delete prototype_factory; return 0; } \ No newline at end of file diff --git a/src/Singleton/Conceptual/Output.txt b/src/Singleton/Conceptual/Output.txt deleted file mode 100644 index 6bcc570..0000000 --- a/src/Singleton/Conceptual/Output.txt +++ /dev/null @@ -1 +0,0 @@ -Singleton works, both variables contain the same instance. \ No newline at end of file diff --git a/src/Singleton/Conceptual/main.cc b/src/Singleton/Conceptual/main.cc deleted file mode 100644 index 1f32b73..0000000 --- a/src/Singleton/Conceptual/main.cc +++ /dev/null @@ -1,125 +0,0 @@ -#include - -/** - * EN: Singleton Design Pattern - * - * Intent: Lets you ensure that a class has only one instance, while providing a - * global access point to this instance. - * - * RU: Паттерн Одиночка - * - * Назначение: Гарантирует, что у класса есть только один экземпляр, и - * предоставляет к нему глобальную точку доступа. - */ -/** - * EN: The Singleton class defines the `GetInstance` method that serves as an - * alternative to constructor and lets clients access the same instance of this - * class over and over. - * - * RU: Класс Одиночка предоставляет метод `GetInstance`, который ведёт себя как - * альтернативный конструктор и позволяет клиентам получать один и тот же - * экземпляр класса при каждом вызове. - */ -class Singleton -{ - - /** - * EN: The Singleton's constructor should always be private to prevent - * direct construction calls with the `new` operator. - * - * RU: Конструктор Одиночки всегда должен быть скрытым, чтобы предотвратить - * создание объекта через оператор new. - */ - -protected: - Singleton() - { - } - -public: - /** - * EN: Singletons should not be cloneable. - * - * RU: Одиночки не должны быть клонируемыми. - */ - Singleton(Singleton &other) = delete; - /** - * EN: Singletons should not be assignable. - * - * RU: - */ - void operator=(const Singleton &) = delete; - /** - * EN: This is the static method that controls the access to the singleton - * instance. On the first run, it creates a singleton object and places it - * into the static field. On subsequent runs, it returns the client existing - * object stored in the static field. - * - * This implementation lets you subclass the Singleton class while keeping - * just one instance of each subclass around. - * - * RU: Это статический метод, управляющий доступом к экземпляру одиночки. - * При первом запуске, он создаёт экземпляр одиночки и помещает его в - * статическое поле. При последующих запусках, он возвращает клиенту объект, - * хранящийся в статическом поле. - * - * Эта реализация позволяет вам расширять класс Одиночки, сохраняя повсюду - * только один экземпляр каждого подкласса. - */ - - static Singleton *GetInstance(); - /** - * EN: Finally, any singleton should define some business logic, which can - * be executed on its instance. - * - * RU: Наконец, любой одиночка должен содержать некоторую бизнес-логику, - * которая может быть выполнена на его экземпляре. - */ - void SomeBusinessLogic() - { - // ... - } -}; - -/** - * EN: Static methods should be defined outside the class. - * - * RU: - */ -Singleton *Singleton::GetInstance() -{ - /** - * EN: This is a safer way to create an instance. instance = new Singleton is dangeruous - * in case two instance threads wants to access at the same time - * - * RU: - */ - static Singleton singleton; - return &singleton; -} - -/** - * EN: The client code. - * - * RU: Клиентский код. - */ -void ClientCode() -{ - Singleton *s1 = Singleton::GetInstance(); - Singleton *s2 = Singleton::GetInstance(); - if (s1 == s2) - { - std::cout << "Singleton works, both variables contain the same instance.\n"; - } - else - { - std::cout << "Singleton failed, variables contain different instances.\n"; - } - delete s1; -} - -int main() -{ - ClientCode(); - return 0; -} \ No newline at end of file From d47e9899f7dd79609c1821477325c339b20274d3 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Thu, 10 Oct 2019 16:14:05 -0500 Subject: [PATCH 20/36] Singleton Multithread fail sample added --- .../Conceptual/NonThreadSafe/Output.txt | 7 +- .../Conceptual/NonThreadSafe/main.cc | 68 ++++++++++++------- .../Conceptual/ThreadSafe/Output.txt | 7 +- src/Singleton/Conceptual/ThreadSafe/main.cc | 68 +++++++++++-------- 4 files changed, 97 insertions(+), 53 deletions(-) diff --git a/src/Singleton/Conceptual/NonThreadSafe/Output.txt b/src/Singleton/Conceptual/NonThreadSafe/Output.txt index 6bcc570..c40891c 100644 --- a/src/Singleton/Conceptual/NonThreadSafe/Output.txt +++ b/src/Singleton/Conceptual/NonThreadSafe/Output.txt @@ -1 +1,6 @@ -Singleton works, both variables contain the same instance. \ No newline at end of file +If you see the same value, then singleton was reused (yay! +If you see different values, then 2 singletons were created (booo!!) + +RESULT: +BAR +FOO \ No newline at end of file diff --git a/src/Singleton/Conceptual/NonThreadSafe/main.cc b/src/Singleton/Conceptual/NonThreadSafe/main.cc index 2334d7f..cf3207b 100644 --- a/src/Singleton/Conceptual/NonThreadSafe/main.cc +++ b/src/Singleton/Conceptual/NonThreadSafe/main.cc @@ -1,4 +1,6 @@ #include +#include +#include /** * EN: Singleton Design Pattern @@ -32,11 +34,16 @@ class Singleton */ protected: - Singleton() + Singleton(const std::string value): value_(value) { } + static Singleton* singleton_; + + std::string value_; + public: + /** * EN: Singletons should not be cloneable. * @@ -63,7 +70,7 @@ class Singleton * */ - static Singleton *GetInstance(); + static Singleton *GetInstance(const std::string& value); /** * EN: Finally, any singleton should define some business logic, which can * be executed on its instance. @@ -75,14 +82,20 @@ class Singleton { // ... } + + std::string value() const{ + return value_; + } }; +Singleton* Singleton::singleton_= nullptr;; + /** * EN: Static methods should be defined outside the class. * * RU: */ -Singleton *Singleton::GetInstance() +Singleton *Singleton::GetInstance(const std::string& value) { /** * EN: This is a safer way to create an instance. instance = new Singleton is dangeruous @@ -90,31 +103,40 @@ Singleton *Singleton::GetInstance() * * RU: */ - static Singleton singleton; - return &singleton; + if(singleton_==nullptr){ + singleton_ = new Singleton(value); + } + return singleton_; } -/** - * EN: The client code. - * - * RU: Клиентский код. - */ -void ClientCode() -{ - Singleton *s1 = Singleton::GetInstance(); - Singleton *s2 = Singleton::GetInstance(); - if (s1 == s2) - { - std::cout << "Singleton works, both variables contain the same instance.\n"; - } - else - { - std::cout << "Singleton failed, variables contain different instances.\n"; - } +void ThreadFoo(){ + // EN: Following code emulates slow initialization. + // + // RU: Этот код эмулирует медленную инициализацию. + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + Singleton* singleton = Singleton::GetInstance("FOO"); + std::cout << singleton->value() << "\n"; } +void ThreadBar(){ + // EN: Following code emulates slow initialization. + // + // RU: Этот код эмулирует медленную инициализацию. + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + Singleton* singleton = Singleton::GetInstance("BAR"); + std::cout << singleton->value() << "\n"; +} + + int main() { - ClientCode(); + std::cout <<"If you see the same value, then singleton was reused (yay!\n" << + "If you see different values, then 2 singletons were created (booo!!)\n\n" << + "RESULT:\n"; + std::thread t1(ThreadFoo); + std::thread t2(ThreadBar); + t1.join(); + t2.join(); + return 0; } \ No newline at end of file diff --git a/src/Singleton/Conceptual/ThreadSafe/Output.txt b/src/Singleton/Conceptual/ThreadSafe/Output.txt index 6bcc570..20d3e7f 100644 --- a/src/Singleton/Conceptual/ThreadSafe/Output.txt +++ b/src/Singleton/Conceptual/ThreadSafe/Output.txt @@ -1 +1,6 @@ -Singleton works, both variables contain the same instance. \ No newline at end of file +If you see the same value, then singleton was reused (yay! +If you see different values, then 2 singletons were created (booo!!) + +RESULT: +FOO +FOO \ No newline at end of file diff --git a/src/Singleton/Conceptual/ThreadSafe/main.cc b/src/Singleton/Conceptual/ThreadSafe/main.cc index fa9d10d..1307cd4 100644 --- a/src/Singleton/Conceptual/ThreadSafe/main.cc +++ b/src/Singleton/Conceptual/ThreadSafe/main.cc @@ -7,6 +7,7 @@ #include #include +#include /** * EN: Singleton Design Pattern @@ -39,14 +40,15 @@ class Singleton * создание объекта через оператор new. */ private: - static Singleton * pinstance; + static Singleton * pinstance_; static std::mutex mutex_; protected: - Singleton() + Singleton(const std::string value): value_(value) { } ~Singleton() {} + std::string value_; public: /** @@ -75,7 +77,7 @@ class Singleton * */ - static Singleton *GetInstance(); + static Singleton *GetInstance(const std::string& value); /** * EN: Finally, any singleton should define some business logic, which can * be executed on its instance. @@ -87,6 +89,10 @@ class Singleton { // ... } + + std::string value() const{ + return value_; + } }; /** @@ -95,7 +101,7 @@ class Singleton * RU: */ -Singleton* Singleton::pinstance{nullptr}; +Singleton* Singleton::pinstance_{nullptr}; std::mutex Singleton::mutex_; /** @@ -104,40 +110,46 @@ std::mutex Singleton::mutex_; * set the value. * RU: */ -Singleton *Singleton::GetInstance() +Singleton *Singleton::GetInstance(const std::string& value) { - if (pinstance == nullptr) + if (pinstance_ == nullptr) { std::lock_guard lock(mutex_); - if (pinstance == nullptr) + if (pinstance_ == nullptr) { - pinstance = new Singleton; + pinstance_ = new Singleton(value); } } - return pinstance; + return pinstance_; } -/** - * EN: The client code. - * - * RU: Клиентский код. - */ -void ClientCode() -{ - Singleton *s1 = Singleton::GetInstance(); - Singleton *s2 = Singleton::GetInstance(); - if (s1 == s2) - { - std::cout << "Singleton works, both variables contain the same instance.\n"; - } - else - { - std::cout << "Singleton failed, variables contain different instances.\n"; - } +void ThreadFoo(){ + // EN: Following code emulates slow initialization. + // + // RU: Этот код эмулирует медленную инициализацию. + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + Singleton* singleton = Singleton::GetInstance("FOO"); + std::cout << singleton->value() << "\n"; +} + +void ThreadBar(){ + // EN: Following code emulates slow initialization. + // + // RU: Этот код эмулирует медленную инициализацию. + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + Singleton* singleton = Singleton::GetInstance("BAR"); + std::cout << singleton->value() << "\n"; } int main() -{ - ClientCode(); +{ + std::cout <<"If you see the same value, then singleton was reused (yay!\n" << + "If you see different values, then 2 singletons were created (booo!!)\n\n" << + "RESULT:\n"; + std::thread t1(ThreadFoo); + std::thread t2(ThreadBar); + t1.join(); + t2.join(); + return 0; } \ No newline at end of file From 2ad64becf1a6ef648def81b426502474a5127458 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Thu, 10 Oct 2019 17:42:25 -0500 Subject: [PATCH 21/36] Complete Adapter with multiple Inheritance example --- .../Conceptual/MultipleInheritance/Output.txt | 10 ++ .../Conceptual/MultipleInheritance/main.cc | 97 +++++++++++++++++++ .../Conceptual/{ => Normal}/Output.txt | 0 src/Adapter/Conceptual/{ => Normal}/main.cc | 0 4 files changed, 107 insertions(+) create mode 100644 src/Adapter/Conceptual/MultipleInheritance/Output.txt create mode 100644 src/Adapter/Conceptual/MultipleInheritance/main.cc rename src/Adapter/Conceptual/{ => Normal}/Output.txt (100%) rename src/Adapter/Conceptual/{ => Normal}/main.cc (100%) diff --git a/src/Adapter/Conceptual/MultipleInheritance/Output.txt b/src/Adapter/Conceptual/MultipleInheritance/Output.txt new file mode 100644 index 0000000..98126ae --- /dev/null +++ b/src/Adapter/Conceptual/MultipleInheritance/Output.txt @@ -0,0 +1,10 @@ +Client: I can work just fine with the Target objects: +Target: The default target's behavior. + +Client: The Adaptee class has a weird interface. See, I don't understand it: +Adaptee: .eetpadA eht fo roivaheb laicepS + +Client: But I can work with it via the Adapter: +Adapter: (TRANSLATED) Special behavior of the Adaptee. + + diff --git a/src/Adapter/Conceptual/MultipleInheritance/main.cc b/src/Adapter/Conceptual/MultipleInheritance/main.cc new file mode 100644 index 0000000..f738af8 --- /dev/null +++ b/src/Adapter/Conceptual/MultipleInheritance/main.cc @@ -0,0 +1,97 @@ +#include +#include +#include +/** + * EN: Adapter Design Pattern + * + * Intent: Provides a unified interface that allows objects with incompatible + * interfaces to collaborate. + * + * RU: Паттерн Адаптер + * + * Назначение: Позволяет объектам с несовместимыми интерфейсами работать вместе. + */ +/** + * EN: The Target defines the domain-specific interface used by the client code. + * + * RU: Целевой класс объявляет интерфейс, с которым может работать клиентский + * код. + */ +class Target +{ +public: + virtual ~Target() = default; + + virtual std::string Request() const + { + return "Target: The default target's behavior."; + } +}; +/** + * EN: The Adaptee contains some useful behavior, but its interface is + * incompatible with the existing client code. The Adaptee needs some adaptation + * before the client code can use it. + * + * RU: Адаптируемый класс содержит некоторое полезное поведение, но его + * интерфейс несовместим с существующим клиентским кодом. Адаптируемый класс + * нуждается в некоторой доработке, прежде чем клиентский код сможет его + * использовать. + */ +class Adaptee +{ +public: + std::string SpecificRequest() const + { + return ".eetpadA eht fo roivaheb laicepS"; + } +}; +/** + * EN: The Adapter makes the Adaptee's interface compatible with the Target's + * interface using multiple inheritance. + * + * RU: + */ +class Adapter : public Target , public Adaptee +{ + +public: + Adapter() { + } + std::string Request() const override + { + std::string to_reverse = SpecificRequest(); + std::reverse(to_reverse.begin(), to_reverse.end()); + return "Adapter: (TRANSLATED) " + to_reverse; + } +}; +/** + * EN: The client code supports all classes that follow the Target interface. + * + * RU: Клиентский код поддерживает все классы, использующие целевой интерфейс. + */ +void ClientCode(const Target *target) +{ + std::cout << target->Request(); +} + +int main() +{ + std::cout << "Client: I can work just fine with the Target objects:\n"; + Target *target = new Target; + ClientCode(target); + std::cout << "\n\n"; + Adaptee *adaptee = new Adaptee; + std::cout << "Client: The Adaptee class has a weird interface. See, I don't understand it:\n"; + std::cout << "Adaptee: " << adaptee->SpecificRequest(); + std::cout << "\n\n"; + std::cout << "Client: But I can work with it via the Adapter:\n"; + Adapter *adapter = new Adapter; + ClientCode(adapter); + std::cout << "\n"; + + delete target; + delete adaptee; + delete adapter; + + return 0; +} diff --git a/src/Adapter/Conceptual/Output.txt b/src/Adapter/Conceptual/Normal/Output.txt similarity index 100% rename from src/Adapter/Conceptual/Output.txt rename to src/Adapter/Conceptual/Normal/Output.txt diff --git a/src/Adapter/Conceptual/main.cc b/src/Adapter/Conceptual/Normal/main.cc similarity index 100% rename from src/Adapter/Conceptual/main.cc rename to src/Adapter/Conceptual/Normal/main.cc From b6e966d318808315b2c183f930d7dab34d19f555 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Thu, 10 Oct 2019 17:44:14 -0500 Subject: [PATCH 22/36] Composite Example --- src/Composite/Conceptual/Output.txt | 9 + src/Composite/Conceptual/main.cc | 263 ++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 src/Composite/Conceptual/Output.txt create mode 100644 src/Composite/Conceptual/main.cc diff --git a/src/Composite/Conceptual/Output.txt b/src/Composite/Conceptual/Output.txt new file mode 100644 index 0000000..156a928 --- /dev/null +++ b/src/Composite/Conceptual/Output.txt @@ -0,0 +1,9 @@ +Client: I've got a simple component: +RESULT: Leaf + +Client: Now I've got a composite tree: +RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)) + +Client: I don't need to check the components classes even when managing the tree: +RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf) + diff --git a/src/Composite/Conceptual/main.cc b/src/Composite/Conceptual/main.cc new file mode 100644 index 0000000..3c865a1 --- /dev/null +++ b/src/Composite/Conceptual/main.cc @@ -0,0 +1,263 @@ + +#include +#include +#include +#include +/** + * EN: Composite Design Pattern + * + * Intent: Lets you compose objects into tree structures and then work with + * these structures as if they were individual objects. + * + * RU: Паттерн Компоновщик + * + * Назначение: Позволяет сгруппировать объекты в древовидную структуру, а затем + * работать с ними так, как будто это единичный объект. + */ +/** + * EN: The base Component class declares common operations for both simple and + * complex objects of a composition. + * + * RU: Базовый класс Компонент объявляет общие операции как для простых, так и + * для сложных объектов структуры. + */ +class Component +{ + /** + * @var Component + */ +protected: + Component *parent_; + /** + * EN: Optionally, the base Component can declare an interface for setting + * and accessing a parent of the component in a tree structure. It can also + * provide some default implementation for these methods. + * + * RU: При необходимости базовый Компонент может объявить интерфейс для + * установки и получения родителя компонента в древовидной структуре. Он + * также может предоставить некоторую реализацию по умолчанию для этих + * методов. + */ +public: + virtual ~Component() {} + void SetParent(Component *parent) + { + this->parent_ = parent; + } + Component *GetParent() const + { + return this->parent_; + } + /** + * EN: In some cases, it would be beneficial to define the child-management + * operations right in the base Component class. This way, you won't need to + * expose any concrete component classes to the client code, even during the + * object tree assembly. The downside is that these methods will be empty + * for the leaf-level components. + * + * RU: В некоторых случаях целесообразно определить операции управления + * потомками прямо в базовом классе Компонент. Таким образом, вам не нужно + * будет предоставлять конкретные классы компонентов клиентскому коду, даже + * во время сборки дерева объектов. Недостаток такого подхода в том, что эти + * методы будут пустыми для компонентов уровня листа. + */ + virtual void Add(Component *component) {} + virtual void Remove(Component *component) {} + /** + * EN: You can provide a method that lets the client code figure out whether + * a component can bear children. + * + * RU: Вы можете предоставить метод, который позволит клиентскому коду + * понять, может ли компонент иметь вложенные объекты. + */ + virtual bool IsComposite() const + { + return false; + } + /** + * EN: The base Component may implement some default behavior or leave it to + * concrete classes (by declaring the method containing the behavior as + * "abstract"). + * + * RU: Базовый Компонент может сам реализовать некоторое поведение по + * умолчанию или поручить это конкретным классам, объявив метод, содержащий + * поведение абстрактным. + */ + virtual std::string Operation() const = 0; +}; +/** + * EN: The Leaf class represents the end objects of a composition. A leaf can't + * have any children. + * + * Usually, it's the Leaf objects that do the actual work, whereas Composite + * objects only delegate to their sub-components. + * + * RU: Класс Лист представляет собой конечные объекты структуры. Лист не может + * иметь вложенных компонентов. + * + * Обычно объекты Листьев выполняют фактическую работу, тогда как объекты + * Контейнера лишь делегируют работу своим подкомпонентам. + */ +class Leaf : public Component +{ +public: + std::string Operation() const override + { + return "Leaf"; + } +}; +/** + * EN: The Composite class represents the complex components that may have + * children. Usually, the Composite objects delegate the actual work to their + * children and then "sum-up" the result. + * + * RU: Класс Контейнер содержит сложные компоненты, которые могут иметь + * вложенные компоненты. Обычно объекты Контейнеры делегируют фактическую работу + * своим детям, а затем «суммируют» результат. + */ +class Composite : public Component +{ + /** + * @var \SplObjectStorage + */ +protected: + std::list children_; + +public: + /** + * EN: A composite object can add or remove other components (both simple or + * complex) to or from its child list. + * + * RU: Объект контейнера может как добавлять компоненты в свой список + * вложенных компонентов, так и удалять их, как простые, так и сложные. + */ + void Add(Component *component) override + { + this->children_.push_back(component); + component->SetParent(this); + } + /** + * EN: Have in mind that this method removes the pointer to the list but doesn't frees the + * memory, you should do it manually or better use smart pointers. + * + * RU: + */ + void Remove(Component *component) override + { + + children_.remove(component); + component->SetParent(nullptr); + } + bool IsComposite() const override + { + return true; + } + /** + * EN: The Composite executes its primary logic in a particular way. It + * traverses recursively through all its children, collecting and summing + * their results. Since the composite's children pass these calls to their + * children and so forth, the whole object tree is traversed as a result. + * + * RU: Контейнер выполняет свою основную логику особым образом. Он проходит + * рекурсивно через всех своих детей, собирая и суммируя их результаты. + * Поскольку потомки контейнера передают эти вызовы своим потомкам и так + * далее, в результате обходится всё дерево объектов. + */ + std::string Operation() const override + { + std::string result; + for (const Component *c : children_) + { + if (c == children_.back()) + { + result += c->Operation(); + } + else + { + result += c->Operation() + "+"; + } + } + return "Branch(" + result + ")"; + } +}; +/** + * EN: The client code works with all of the components via the base interface. + * + * RU: Клиентский код работает со всеми компонентами через базовый интерфейс. + */ +void ClientCode(Component *component) +{ + // ... + std::cout << "RESULT: " << component->Operation(); + // ... +} + +/** + * EN: Thanks to the fact that the child-management operations are declared in + * the base Component class, the client code can work with any component, simple + * or complex, without depending on their concrete classes. + * + * RU: Благодаря тому, что операции управления потомками объявлены в базовом + * классе Компонента, клиентский код может работать как с простыми, так и со + * сложными компонентами, вне зависимости от их конкретных классов. + */ +void ClientCode2(Component *component1, Component *component2) +{ + // ... + if (component1->IsComposite()) + { + component1->Add(component2); + } + std::cout << "RESULT: " << component1->Operation(); + // ... +} + +/** + * EN: This way the client code can support the simple leaf components... + * + * RU: Таким образом, клиентский код может поддерживать простые + * компоненты-листья... + */ + +int main() +{ + Component *simple = new Leaf; + std::cout << "Client: I've got a simple component:\n"; + ClientCode(simple); + std::cout << "\n\n"; + /** + * EN: ...as well as the complex composites. + * + * RU: ...а также сложные контейнеры. + */ + + Component *tree = new Composite; + Component *branch1 = new Composite; + + Component *leaf_1 = new Leaf; + Component *leaf_2 = new Leaf; + Component *leaf_3 = new Leaf; + branch1->Add(leaf_1); + branch1->Add(leaf_2); + Component *branch2 = new Composite; + branch2->Add(leaf_3); + tree->Add(branch1); + tree->Add(branch2); + std::cout << "Client: Now I've got a composite tree:\n"; + ClientCode(tree); + std::cout << "\n\n"; + + std::cout << "Client: I don't need to check the components classes even when managing the tree:\n"; + ClientCode2(tree, simple); + std::cout << "\n"; + + delete simple; + delete tree; + delete branch1; + delete branch2; + delete leaf_1; + delete leaf_2; + delete leaf_3; + + return 0; +} From e64c597235ff9c120831fdee1f9fc7c6b14cf944 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Fri, 11 Oct 2019 10:57:00 -0500 Subject: [PATCH 23/36] facade and decorator Pattern --- src/Decorator/Conceptual/Output.txt | 6 + src/Decorator/Conceptual/main.cc | 176 ++++++++++++++++++++++++++++ src/Facade/Conceptual/Output.txt | 7 ++ src/Facade/Conceptual/main.cc | 159 +++++++++++++++++++++++++ 4 files changed, 348 insertions(+) create mode 100644 src/Decorator/Conceptual/Output.txt create mode 100644 src/Decorator/Conceptual/main.cc create mode 100644 src/Facade/Conceptual/Output.txt create mode 100644 src/Facade/Conceptual/main.cc diff --git a/src/Decorator/Conceptual/Output.txt b/src/Decorator/Conceptual/Output.txt new file mode 100644 index 0000000..ed793df --- /dev/null +++ b/src/Decorator/Conceptual/Output.txt @@ -0,0 +1,6 @@ +Client: I've got a simple component: +RESULT: ConcreteComponent + +Client: Now I've got a decorated component: +RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent)) + diff --git a/src/Decorator/Conceptual/main.cc b/src/Decorator/Conceptual/main.cc new file mode 100644 index 0000000..4a8b02b --- /dev/null +++ b/src/Decorator/Conceptual/main.cc @@ -0,0 +1,176 @@ +#include +#include + +/** + * EN: Decorator Design Pattern + * + * Intent: Lets you attach new behaviors to objects by placing these objects + * inside special wrapper objects that contain the behaviors. + * + * RU: Паттерн Декоратор + * + * Назначение: Позволяет динамически добавлять объектам новую функциональность, + * оборачивая их в полезные «обёртки». + */ +/** + * EN: The base Component interface defines operations that can be altered by + * decorators. + * + * RU: Базовый интерфейс Компонента определяет поведение, которое изменяется + * декораторами. + */ +class Component +{ +public: + virtual ~Component() {} + virtual std::string Operation() const = 0; +}; +/** + * EN: Concrete Components provide default implementations of the operations. + * There might be several variations of these classes. + * + * RU: Конкретные Компоненты предоставляют реализации поведения по умолчанию. + * Может быть несколько вариаций этих классов. + */ +class ConcreteComponent : public Component +{ +public: + std::string Operation() const override + { + return "ConcreteComponent"; + } +}; +/** + * EN: The base Decorator class follows the same interface as the other + * components. The primary purpose of this class is to define the wrapping + * interface for all concrete decorators. The default implementation of the + * wrapping code might include a field for storing a wrapped component and the + * means to initialize it. + * + * RU: Базовый класс Декоратора следует тому же интерфейсу, что и другие + * компоненты. Основная цель этого класса - определить интерфейс обёртки для + * всех конкретных декораторов. Реализация кода обёртки по умолчанию может + * включать в себя поле для хранения завёрнутого компонента и средства его + * инициализации. + */ +class Decorator : public Component +{ + /** + * @var Component + */ +protected: + Component *component_; + +public: + Decorator(Component *component) : component_(component) + { + } + /** + * EN: The Decorator delegates all work to the wrapped component. + * + * RU: Декоратор делегирует всю работу обёрнутому компоненту. + */ + std::string Operation() const override + { + return this->component_->Operation(); + } +}; +/** + * EN: Concrete Decorators call the wrapped object and alter its result in some + * way. + * + * RU: Конкретные Декораторы вызывают обёрнутый объект и изменяют его результат + * некоторым образом. + */ +class ConcreteDecoratorA : public Decorator +{ + /** + * EN: Decorators may call parent implementation of the operation, instead + * of calling the wrapped object directly. This approach simplifies + * extension of decorator classes. + * + * RU: Декораторы могут вызывать родительскую реализацию операции, вместо + * того, чтобы вызвать обёрнутый объект напрямую. Такой подход упрощает + * расширение классов декораторов. + */ +public: + + ConcreteDecoratorA(Component* component): Decorator(component){ + + } + std::string Operation() const override + { + return "ConcreteDecoratorA(" + Decorator::Operation() + ")"; + } +}; +/** + * EN: Decorators can execute their behavior either before or after the call to + * a wrapped object. + * + * RU: Декораторы могут выполнять своё поведение до или после вызова обёрнутого + * объекта. + */ +class ConcreteDecoratorB : public Decorator +{ +public: + + ConcreteDecoratorB(Component* component): Decorator(component){ + + } + + std::string Operation() const override + { + return "ConcreteDecoratorB(" + Decorator::Operation() + ")"; + } +}; +/** + * EN: The client code works with all objects using the Component interface. + * This way it can stay independent of the concrete classes of components it + * works with. + * + * RU: Клиентский код работает со всеми объектами, используя интерфейс + * Компонента. Таким образом, он остаётся независимым от конкретных классов + * компонентов, с которыми работает. + */ +void ClientCode(Component *component) +{ + // ... + std::cout << "RESULT: " << component->Operation(); + // ... +} + +int main() +{ + /** + * EN: This way the client code can support both simple components... + * + * RU: Таким образом, клиентский код может поддерживать как простые + * компоненты... + */ + Component* simple = new ConcreteComponent; + std::cout << "Client: I've got a simple component:\n"; + ClientCode(simple); + std::cout << "\n\n"; + /** + * EN: ...as well as decorated ones. + * + * Note how decorators can wrap not only simple components but the other + * decorators as well. + * + * RU: ...так и декорированные. + * + * Обратите внимание, что декораторы могут обёртывать не только простые + * компоненты, но и другие декораторы. + */ + Component* decorator1 = new ConcreteDecoratorA(simple); + Component* decorator2 = new ConcreteDecoratorB(decorator1); + std::cout << "Client: Now I've got a decorated component:\n"; + ClientCode(decorator2); + std::cout << "\n"; + + delete simple; + delete decorator1; + delete decorator2; + + return 0; +} \ No newline at end of file diff --git a/src/Facade/Conceptual/Output.txt b/src/Facade/Conceptual/Output.txt new file mode 100644 index 0000000..a9dcd58 --- /dev/null +++ b/src/Facade/Conceptual/Output.txt @@ -0,0 +1,7 @@ +Facade initializes subsystems: +Subsystem1: Ready! +Subsystem2: Get ready! +Facade orders subsystems to perform the action: +Subsystem1: Go! +Subsystem2: Fire! + diff --git a/src/Facade/Conceptual/main.cc b/src/Facade/Conceptual/main.cc new file mode 100644 index 0000000..d3a3ad0 --- /dev/null +++ b/src/Facade/Conceptual/main.cc @@ -0,0 +1,159 @@ +#include +#include + +/** + * EN: Facade Design Pattern + * + * Intent: Provides a simplified interface to a library, a framework, or any + * other complex set of classes. + * + * RU: Паттерн Фасад + * + * Назначение: Предоставляет простой интерфейс к сложной системе классов, + * библиотеке или фреймворку. + */ + +/** + * EN: The Subsystem can accept requests either from the facade or client + * directly. In any case, to the Subsystem, the Facade is yet another client, + * and it's not a part of the Subsystem. + * + * RU: Подсистема может принимать запросы либо от фасада, либо от клиента + * напрямую. В любом случае, для Подсистемы Фасад – это еще один клиент, и он не + * является частью Подсистемы. + */ +class Subsystem1 +{ +public: + std::string Operation1() const + { + return "Subsystem1: Ready!\n"; + } + // ... + std::string OperationN() const + { + return "Subsystem1: Go!\n"; + } +}; +/** + * EN: Some facades can work with multiple subsystems at the same time. + * + * RU: Некоторые фасады могут работать с разными подсистемами одновременно. + */ +class Subsystem2 +{ +public: + std::string Operation1() const + { + return "Subsystem2: Get ready!\n"; + } + // ... + std::string OperationZ() const + { + return "Subsystem2: Fire!\n"; + } +}; + +/** + * EN: The Facade class provides a simple interface to the complex logic of one + * or several subsystems. The Facade delegates the client requests to the + * appropriate objects within the subsystem. The Facade is also responsible for + * managing their lifecycle. All of this shields the client from the undesired + * complexity of the subsystem. + * + * RU: Класс Фасада предоставляет простой интерфейс для сложной логики одной или + * нескольких подсистем. Фасад делегирует запросы клиентов соответствующим + * объектам внутри подсистемы. Фасад также отвечает за управление их жизненным + * циклом. Все это защищает клиента от нежелательной сложности подсистемы. + */ +class Facade +{ +protected: + Subsystem1 *subsystem1_; + Subsystem2 *subsystem2_; + /** + * EN: Depending on your application's needs, you can provide the Facade + * with existing subsystem objects or force the Facade to create them on its + * own. + * + * RU: В зависимости от потребностей вашего приложения вы можете + * предоставить Фасаду существующие объекты подсистемы или заставить Фасад + * создать их самостоятельно. + */ +public: + /** + * EN: In this case we will delegate the memory ownership to Facade Class + * + * RU: + */ + Facade( + Subsystem1 *subsystem1 = nullptr, + Subsystem2 *subsystem2 = nullptr) + { + this->subsystem1_ = subsystem1 ?: new Subsystem1; + this->subsystem2_ = subsystem2 ?: new Subsystem2; + } + ~Facade() + { + delete subsystem1_; + delete subsystem2_; + } + /** + * EN: The Facade's methods are convenient shortcuts to the sophisticated + * functionality of the subsystems. However, clients get only to a fraction + * of a subsystem's capabilities. + * + * RU: Методы Фасада удобны для быстрого доступа к сложной функциональности + * подсистем. Однако клиенты получают только часть возможностей подсистемы. + */ + std::string Operation() + { + std::string result = "Facade initializes subsystems:\n"; + result += this->subsystem1_->Operation1(); + result += this->subsystem2_->Operation1(); + result += "Facade orders subsystems to perform the action:\n"; + result += this->subsystem1_->OperationN(); + result += this->subsystem2_->OperationZ(); + return result; + } +}; + +/** + * EN: The client code works with complex subsystems through a simple interface + * provided by the Facade. When a facade manages the lifecycle of the subsystem, + * the client might not even know about the existence of the subsystem. This + * approach lets you keep the complexity under control. + * + * RU: Клиентский код работает со сложными подсистемами через простой интерфейс, + * предоставляемый Фасадом. Когда фасад управляет жизненным циклом подсистемы, + * клиент может даже не знать о существовании подсистемы. Такой подход позволяет + * держать сложность под контролем. + */ +void ClientCode(Facade *facade) +{ + // ... + std::cout << facade->Operation(); + // ... +} +/** + * EN: The client code may have some of the subsystem's objects already created. + * In this case, it might be worthwhile to initialize the Facade with these + * objects instead of letting the Facade create new instances. + * + * RU: В клиентском коде могут быть уже созданы некоторые объекты подсистемы. В + * этом случае может оказаться целесообразным инициализировать Фасад с этими + * объектами вместо того, чтобы позволить Фасаду создавать новые экземпляры. + */ + +int main() +{ + + Subsystem1 *subsystem1 = new Subsystem1; + Subsystem2 *subsystem2 = new Subsystem2; + Facade *facade = new Facade(subsystem1, subsystem2); + ClientCode(facade); + + delete facade; + + return 0; +} From a8ae0915a2930fc33d5417bd6482b7a606be757e Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 16 Oct 2019 15:22:23 -0500 Subject: [PATCH 24/36] Flyweight pattern --- src/Flyweight/Conceptual/Output.txt | 22 +++ src/Flyweight/Conceptual/main.cc | 203 ++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 src/Flyweight/Conceptual/Output.txt create mode 100644 src/Flyweight/Conceptual/main.cc diff --git a/src/Flyweight/Conceptual/Output.txt b/src/Flyweight/Conceptual/Output.txt new file mode 100644 index 0000000..6a70e03 --- /dev/null +++ b/src/Flyweight/Conceptual/Output.txt @@ -0,0 +1,22 @@ +FlyweightFactory: I have 5 flyweights: +BMW_X6_white +Mercedes Benz_C500_red +Mercedes Benz_C300_black +BMW_M5_red +Chevrolet_Camaro2018_pink + +Client: Adding a car to database. +FlyweightFactory: Reusing existing flyweight. +Flyweight: Displaying shared ([ BMW , M5 , red ]) and unique ([ CL234IR , James Doe ]) state. + +Client: Adding a car to database. +FlyweightFactory: Can't find a flyweight, creating new one. +Flyweight: Displaying shared ([ BMW , X1 , red ]) and unique ([ CL234IR , James Doe ]) state. + +FlyweightFactory: I have 6 flyweights: +BMW_X1_red +Mercedes Benz_C300_black +BMW_X6_white +Mercedes Benz_C500_red +BMW_M5_red +Chevrolet_Camaro2018_pink \ No newline at end of file diff --git a/src/Flyweight/Conceptual/main.cc b/src/Flyweight/Conceptual/main.cc new file mode 100644 index 0000000..7868e99 --- /dev/null +++ b/src/Flyweight/Conceptual/main.cc @@ -0,0 +1,203 @@ +#include +#include +#include +#include + +/** + * EN: Flyweight Design Pattern + * + * Intent: Lets you fit more objects into the available amount of RAM by sharing + * common parts of state between multiple objects, instead of keeping all of the + * data in each object. + * + * RU: Паттерн Легковес + * + * Назначение: Позволяет вместить бóльшее количество объектов в отведённую + * оперативную память. Легковес экономит память, разделяя общее состояние + * объектов между собой, вместо хранения одинаковых данных в каждом объекте. + */ + +struct SharedState +{ + std::string brand_; + std::string model_; + std::string color_; + + SharedState(const std::string &brand, const std::string &model, const std::string &color) + : brand_(brand), model_(model), color_(color) + { + } + + friend std::ostream &operator<<(std::ostream &os, const SharedState &ss) + { + return os << "[ " << ss.brand_ << " , " << ss.model_ << " , " << ss.color_ << " ]"; + } +}; + +struct UniqueState +{ + std::string owner_; + std::string plates_; + + UniqueState(const std::string &owner, const std::string &plates) + : owner_(owner), plates_(plates) + { + } + + friend std::ostream &operator<<(std::ostream &os, const UniqueState &us) + { + return os << "[ " << us.owner_ << " , " << us.plates_ << " ]"; + } +}; + +/** + * EN: The Flyweight stores a common portion of the state (also called intrinsic + * state) that belongs to multiple real business entities. The Flyweight accepts + * the rest of the state (extrinsic state, unique for each entity) via its + * method parameters. + * + * RU: Легковес хранит общую часть состояния (также называемую внутренним + * состоянием), которая принадлежит нескольким реальным бизнес-объектам. + * Легковес принимает оставшуюся часть состояния (внешнее состояние, уникальное + * для каждого объекта) через его параметры метода. + */ +class Flyweight +{ +private: + SharedState *shared_state_; + +public: + Flyweight(const SharedState *shared_state) : shared_state_(new SharedState(*shared_state)) + { + } + Flyweight(const Flyweight &other) : shared_state_(new SharedState(*other.shared_state_)) + { + } + ~Flyweight() + { + delete shared_state_; + } + SharedState *shared_state() const + { + return shared_state_; + } + void Operation(const UniqueState &unique_state) const + { + std::cout << "Flyweight: Displaying shared (" << *shared_state_ << ") and unique (" << unique_state << ") state.\n"; + } +}; +/** + * EN: The Flyweight Factory creates and manages the Flyweight objects. It + * ensures that flyweights are shared correctly. When the client requests a + * flyweight, the factory either returns an existing instance or creates a new + * one, if it doesn't exist yet. + * + * RU: Фабрика Легковесов создает объекты-Легковесы и управляет ими. Она + * обеспечивает правильное разделение легковесов. Когда клиент запрашивает + * легковес, фабрика либо возвращает существующий экземпляр, либо создает новый, + * если он ещё не существует. + */ +class FlyweightFactory +{ + /** + * @var Flyweight[] + */ +private: + std::unordered_map flyweights_; + /** + * EN: Returns a Flyweight's string hash for a given state. + * + * RU: Возвращает хеш строки Легковеса для данного состояния. + */ + std::string GetKey(const SharedState &ss) const + { + return ss.brand_ + "_" + ss.model_ + "_" + ss.color_; + } + +public: + FlyweightFactory(std::initializer_list share_states) + { + for (const SharedState &ss : share_states) + { + this->flyweights_.insert(std::make_pair(this->GetKey(ss), Flyweight(&ss))); + } + } + + /** + * EN: Returns an existing Flyweight with a given state or creates a new + * one. + * + * RU: Возвращает существующий Легковес с заданным состоянием или создает + * новый. + */ + Flyweight GetFlyweight(const SharedState &shared_state) + { + std::string key = this->GetKey(shared_state); + if (this->flyweights_.find(key) == this->flyweights_.end()) + { + std::cout << "FlyweightFactory: Can't find a flyweight, creating new one.\n"; + this->flyweights_.insert(std::make_pair(key, Flyweight(&shared_state))); + } + else + { + std::cout << "FlyweightFactory: Reusing existing flyweight.\n"; + } + return this->flyweights_.at(key); + } + void ListFlyweights() const + { + size_t count = this->flyweights_.size(); + std::cout << "\nFlyweightFactory: I have " << count << " flyweights:\n"; + for (std::pair pair : this->flyweights_) + { + std::cout << pair.first << "\n"; + } + } +}; + +// ... +void AddCarToPoliceDatabase( + FlyweightFactory &ff, const std::string &plates, const std::string &owner, + const std::string &brand, const std::string &model, const std::string &color) +{ + std::cout << "\nClient: Adding a car to database.\n"; + const Flyweight &flyweight = ff.GetFlyweight({brand, model, color}); + // EN: The client code either stores or calculates extrinsic state and + // passes it to the flyweight's methods. + // + // RU: Клиентский код либо сохраняет, либо вычисляет внешнее состояние и + // передает его методам легковеса. + flyweight.Operation({plates, owner}); +} + +/** + * EN: The client code usually creates a bunch of pre-populated flyweights in + * the initialization stage of the application. + * + * RU: Клиентский код обычно создает кучу предварительно заполненных легковесов + * на этапе инициализации приложения. + */ + +int main() +{ + FlyweightFactory *factory = new FlyweightFactory({{"Chevrolet", "Camaro2018", "pink"}, {"Mercedes Benz", "C300", "black"}, {"Mercedes Benz", "C500", "red"}, {"BMW", "M5", "red"}, {"BMW", "X6", "white"}}); + factory->ListFlyweights(); + + AddCarToPoliceDatabase(*factory, + "CL234IR", + "James Doe", + "BMW", + "M5", + "red"); + + AddCarToPoliceDatabase(*factory, + "CL234IR", + "James Doe", + "BMW", + "X1", + "red"); + factory->ListFlyweights(); + delete factory; + + return 0; +} From bb4323a651cf4d3f77ae13520cb3366ee4b4144b Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Wed, 16 Oct 2019 16:34:06 -0500 Subject: [PATCH 25/36] add Proxy --- src/Proxy/Conceptual/Output.txt | 7 ++ src/Proxy/Conceptual/main.cc | 146 ++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/Proxy/Conceptual/Output.txt create mode 100644 src/Proxy/Conceptual/main.cc diff --git a/src/Proxy/Conceptual/Output.txt b/src/Proxy/Conceptual/Output.txt new file mode 100644 index 0000000..057b829 --- /dev/null +++ b/src/Proxy/Conceptual/Output.txt @@ -0,0 +1,7 @@ +Client: Executing the client code with a real subject: +RealSubject: Handling request. + +Client: Executing the same client code with a proxy: +Proxy: Checking access prior to firing a real request. +RealSubject: Handling request. +Proxy: Logging the time of request. \ No newline at end of file diff --git a/src/Proxy/Conceptual/main.cc b/src/Proxy/Conceptual/main.cc new file mode 100644 index 0000000..aeb666f --- /dev/null +++ b/src/Proxy/Conceptual/main.cc @@ -0,0 +1,146 @@ +#include +/** + * EN: Proxy Design Pattern + * + * Intent: Provide a surrogate or placeholder for another object to control + * access to the original object or to add other responsibilities. + * + * RU: Паттерн Заместитель + * + * Назначение: Позволяет подставлять вместо реальных объектов специальные + * объекты-заменители. Эти объекты перехватывают вызовы к оригинальному объекту, + * позволяя сделать что-то до или после передачи вызова оригиналу. + */ +/** + * EN: The Subject interface declares common operations for both RealSubject and + * the Proxy. As long as the client works with RealSubject using this interface, + * you'll be able to pass it a proxy instead of a real subject. + * + * RU: Интерфейс Субъекта объявляет общие операции как для Реального Субъекта, + * так и для Заместителя. Пока клиент работает с Реальным Субъектом, используя + * этот интерфейс, вы сможете передать ему заместителя вместо реального + * субъекта. + */ +class Subject +{ +public: + virtual void Request() const = 0; +}; +/** + * EN: The RealSubject contains some core business logic. Usually, RealSubjects + * are capable of doing some useful work which may also be very slow or + * sensitive - e.g. correcting input data. A Proxy can solve these issues + * without any changes to the RealSubject's code. + * + * RU: Реальный Субъект содержит некоторую базовую бизнес-логику. Как правило, + * Реальные Субъекты способны выполнять некоторую полезную работу, которая к + * тому же может быть очень медленной или точной – например, коррекция входных + * данных. Заместитель может решить эти задачи без каких-либо изменений в коде + * Реального Субъекта. + */ +class RealSubject : public Subject +{ +public: + void Request() const override + { + std::cout << "RealSubject: Handling request.\n"; + } +}; +/** + * EN: The Proxy has an interface identical to the RealSubject. + * + * RU: Интерфейс Заместителя идентичен интерфейсу Реального Субъекта. + */ +class Proxy : public Subject +{ + /** + * @var RealSubject + */ +private: + RealSubject *real_subject_; + + bool CheckAccess() const + { + // EN: Some real checks should go here. + // + // RU: Некоторые реальные проверки должны проходить здесь. + std::cout << "Proxy: Checking access prior to firing a real request.\n"; + return true; + } + void LogAccess() const + { + std::cout << "Proxy: Logging the time of request.\n"; + } + + /** + * EN: The Proxy maintains a reference to an object of the RealSubject + * class. It can be either lazy-loaded or passed to the Proxy by the client. + * + * RU: Заместитель хранит ссылку на объект класса РеальныйСубъект. Клиент + * может либо лениво загрузить его, либо передать Заместителю. + */ +public: + Proxy(RealSubject *real_subject) : real_subject_(new RealSubject(*real_subject)) + { + } + + ~Proxy() + { + delete real_subject_; + } + /** + * EN: The most common applications of the Proxy pattern are lazy loading, + * caching, controlling the access, logging, etc. A Proxy can perform one of + * these things and then, depending on the result, pass the execution to the + * same method in a linked RealSubject object. + * + * RU: Наиболее распространёнными областями применения паттерна Заместитель + * являются ленивая загрузка, кэширование, контроль доступа, ведение журнала + * и т.д. Заместитель может выполнить одну из этих задач, а затем, в + * зависимости от результата, передать выполнение одноимённому методу в + * связанном объекте класса Реального Субъект. + */ + void Request() const override + { + if (this->CheckAccess()) + { + this->real_subject_->Request(); + this->LogAccess(); + } + } +}; +/** + * EN: The client code is supposed to work with all objects (both subjects and + * proxies) via the Subject interface in order to support both real subjects and + * proxies. In real life, however, clients mostly work with their real subjects + * directly. In this case, to implement the pattern more easily, you can extend + * your proxy from the real subject's class. + * + * RU: Клиентский код должен работать со всеми объектами (как с реальными, так и + * заместителями) через интерфейс Субъекта, чтобы поддерживать как реальные + * субъекты, так и заместителей. В реальной жизни, однако, клиенты в основном + * работают с реальными субъектами напрямую. В этом случае, для более простой + * реализации паттерна, можно расширить заместителя из класса реального + * субъекта. + */ +void ClientCode(const Subject &subject) +{ + // ... + subject.Request(); + // ... +} + +int main() +{ + std::cout << "Client: Executing the client code with a real subject:\n"; + RealSubject *real_subject = new RealSubject; + ClientCode(*real_subject); + std::cout << "\n"; + std::cout << "Client: Executing the same client code with a proxy:\n"; + Proxy *proxy = new Proxy(real_subject); + ClientCode(*proxy); + + delete real_subject; + delete proxy; + return 0; +} From c4c3ebf10f4f1b2f7a19d40d6cafb27260e07c6c Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Thu, 17 Oct 2019 09:28:31 -0500 Subject: [PATCH 26/36] Chain of responsability pattern --- .../Conceptual/Output.txt | 17 ++ src/ChainOfResponsability/Conceptual/main.cc | 179 ++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 src/ChainOfResponsability/Conceptual/Output.txt create mode 100644 src/ChainOfResponsability/Conceptual/main.cc diff --git a/src/ChainOfResponsability/Conceptual/Output.txt b/src/ChainOfResponsability/Conceptual/Output.txt new file mode 100644 index 0000000..b213c2f --- /dev/null +++ b/src/ChainOfResponsability/Conceptual/Output.txt @@ -0,0 +1,17 @@ +Chain: Monkey > Squirrel > Dog + +Client: Who wants a Nut? + Squirrel: I'll eat the Nut. +Client: Who wants a Banana? + Monkey: I'll eat the Banana. +Client: Who wants a Cup of coffee? + Cup of coffee was left untouched. + +Subchain: Squirrel > Dog + +Client: Who wants a Nut? + Squirrel: I'll eat the Nut. +Client: Who wants a Banana? + Banana was left untouched. +Client: Who wants a Cup of coffee? + Cup of coffee was left untouched. \ No newline at end of file diff --git a/src/ChainOfResponsability/Conceptual/main.cc b/src/ChainOfResponsability/Conceptual/main.cc new file mode 100644 index 0000000..a2f617e --- /dev/null +++ b/src/ChainOfResponsability/Conceptual/main.cc @@ -0,0 +1,179 @@ +#include +#include +#include + +/** + * EN: Chain of Responsibility Design Pattern + * + * Intent: Lets you pass requests along a chain of handlers. Upon receiving a + * request, each handler decides either to process the request or to pass it to + * the next handler in the chain. + * + * RU: Паттерн Цепочка обязанностей + * + * Назначение: Позволяет передавать запросы последовательно по цепочке + * обработчиков. Каждый последующий обработчик решает, может ли он обработать + * запрос сам и стоит ли передавать запрос дальше по цепи. + */ +/** + * EN: The Handler interface declares a method for building the chain of + * handlers. It also declares a method for executing a request. + * + * RU: Интерфейс Обработчика объявляет метод построения цепочки обработчиков. Он + * также объявляет метод для выполнения запроса. + */ +class Handler +{ +public: + virtual Handler *SetNext(Handler *handler) = 0; + virtual std::string Handle(std::string request) = 0; +}; +/** + * EN: The default chaining behavior can be implemented inside a base handler + * class. + * + * RU: Поведение цепочки по умолчанию может быть реализовано внутри базового + * класса обработчика. + */ +class AbstractHandler : public Handler +{ + /** + * @var Handler + */ +private: + Handler *next_handler_; + +public: + AbstractHandler() : next_handler_(nullptr) + { + } + Handler *SetNext(Handler *handler) override + { + this->next_handler_ = handler; + // EN: Returning a handler from here will let us link handlers in a + // convenient way like this: + // $monkey->setNext($squirrel)->setNext($dog); + // + // RU: Возврат обработчика отсюда позволит связать обработчики простым + // способом, вот так: + // $monkey->setNext($squirrel)->setNext($dog); + return handler; + } + std::string Handle(std::string request) override + { + if (this->next_handler_) + { + return this->next_handler_->Handle(request); + } + + return {}; + } +}; +/** + * EN: All Concrete Handlers either handle a request or pass it to the next + * handler in the chain. + * + * RU: Все Конкретные Обработчики либо обрабатывают запрос, либо передают его + * следующему обработчику в цепочке. + */ +class MonkeyHandler : public AbstractHandler +{ +public: + std::string Handle(std::string request) override + { + if (request == "Banana") + { + return "Monkey: I'll eat the " + request + ".\n"; + } + else + { + return AbstractHandler::Handle(request); + } + } +}; +class SquirrelHandler : public AbstractHandler +{ +public: + std::string Handle(std::string request) override + { + if (request == "Nut") + { + return "Squirrel: I'll eat the " + request + ".\n"; + } + else + { + return AbstractHandler::Handle(request); + } + } +}; +class DogHandler : public AbstractHandler +{ +public: + std::string Handle(std::string request) override + { + if (request == "MeatBall") + { + return "Dog: I'll eat the " + request + ".\n"; + } + else + { + return AbstractHandler::Handle(request); + } + } +}; +/** + * EN: The client code is usually suited to work with a single handler. In most + * cases, it is not even aware that the handler is part of a chain. + * + * RU: Обычно клиентский код приспособлен для работы с единственным + * обработчиком. В большинстве случаев клиенту даже неизвестно, что этот + * обработчик является частью цепочки. + */ +void ClientCode(Handler &handler) +{ + std::vector food = {"Nut", "Banana", "Cup of coffee"}; + for (const std::string &f : food) + { + std::cout << "Client: Who wants a " << f << "?\n"; + const std::string result = handler.Handle(f); + if (!result.empty()) + { + std::cout << " " << result; + } + else + { + std::cout << " " << f << " was left untouched.\n"; + } + } +} +/** + * EN: The other part of the client code constructs the actual chain. + * + * RU: Другая часть клиентского кода создает саму цепочку. + */ +int main() +{ + MonkeyHandler *monkey = new MonkeyHandler; + SquirrelHandler *squirrel = new SquirrelHandler; + DogHandler *dog = new DogHandler; + monkey->SetNext(squirrel)->SetNext(dog); + + /** + * EN: The client should be able to send a request to any handler, not just the + * first one in the chain. + * + * RU: Клиент должен иметь возможность отправлять запрос любому обработчику, а + * не только первому в цепочке. + */ + std::cout << "Chain: Monkey > Squirrel > Dog\n\n"; + ClientCode(*monkey); + std::cout << "\n"; + std::cout << "Subchain: Squirrel > Dog\n\n"; + ClientCode(*squirrel); + + delete monkey; + delete squirrel; + delete dog; + + return 0; +} From fc41083ab96390105800bb98f8021def531f12be Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Thu, 17 Oct 2019 10:41:58 -0500 Subject: [PATCH 27/36] Command Pattern --- src/Command/Conceptual/Output.txt | 7 ++ src/Command/Conceptual/main.cc | 198 ++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 src/Command/Conceptual/Output.txt create mode 100644 src/Command/Conceptual/main.cc diff --git a/src/Command/Conceptual/Output.txt b/src/Command/Conceptual/Output.txt new file mode 100644 index 0000000..d2efc99 --- /dev/null +++ b/src/Command/Conceptual/Output.txt @@ -0,0 +1,7 @@ +Invoker: Does anybody want something done before I begin? +SimpleCommand: See, I can do simple things like printing (Say Hi!) +Invoker: ...doing something really important... +Invoker: Does anybody want something done after I finish? +ComplexCommand: Complex stuff should be done by a receiver object. +Receiver: Working on (Send email.) +Receiver: Also working on (Save report.) \ No newline at end of file diff --git a/src/Command/Conceptual/main.cc b/src/Command/Conceptual/main.cc new file mode 100644 index 0000000..29f9bea --- /dev/null +++ b/src/Command/Conceptual/main.cc @@ -0,0 +1,198 @@ +#include +#include + +/** + * EN: Command Design Pattern + * + * Intent: Turns a request into a stand-alone object that contains all + * information about the request. This transformation lets you parameterize + * methods with different requests, delay or queue a request's execution, and + * support undoable operations. + * + * RU: Паттерн Команда + * + * Назначение: Превращает запросы в объекты, позволяя передавать их как + * аргументы при вызове методов, ставить запросы в очередь, логировать их, а + * также поддерживать отмену операций. + */ +/** + * EN: The Command interface declares a method for executing a command. + * + * RU: Интерфейс Команды объявляет метод для выполнения команд. + */ +class Command +{ +public: + virtual ~Command() + { + } + virtual void Execute() const = 0; +}; +/** + * EN: Some commands can implement simple operations on their own. + * + * RU: Некоторые команды способны выполнять простые операции самостоятельно. + */ +class SimpleCommand : public Command +{ +private: + std::string pay_load_; + +public: + explicit SimpleCommand(std::string pay_load) : pay_load_(pay_load) + { + } + void Execute() const override + { + std::cout << "SimpleCommand: See, I can do simple things like printing (" << this->pay_load_ << ")\n"; + } +}; + +/** + * EN: The Receiver classes contain some important business logic. They know how + * to perform all kinds of operations, associated with carrying out a request. + * In fact, any class may serve as a Receiver. + * + * RU: Классы Получателей содержат некую важную бизнес-логику. Они умеют + * выполнять все виды операций, связанных с выполнением запроса. Фактически, + * любой класс может выступать Получателем. + */ +class Receiver +{ +public: + void DoSomething(const std::string &a) + { + std::cout << "Receiver: Working on (" << a << ".)\n"; + } + void DoSomethingElse(const std::string &b) + { + std::cout << "Receiver: Also working on (" << b << ".)\n"; + } +}; + +/** + * EN: However, some commands can delegate more complex operations to other + * objects, called "receivers." + * + * RU: Но есть и команды, которые делегируют более сложные операции другим + * объектам, называемым «получателями». + */ +class ComplexCommand : public Command +{ + /** + * @var Receiver + */ +private: + Receiver *receiver_; + /** + * EN: Context data, required for launching the receiver's methods. + * + * RU: Данные о контексте, необходимые для запуска методов получателя. + */ + std::string a_; + std::string b_; + /** + * EN: Complex commands can accept one or several receiver objects along + * with any context data via the constructor. + * + * RU: Сложные команды могут принимать один или несколько + * объектов-получателей вместе с любыми данными о контексте через + * конструктор. + */ +public: + ComplexCommand(Receiver *receiver, std::string a, std::string b) : receiver_(receiver), a_(a), b_(b) + { + } + /** + * EN: Commands can delegate to any methods of a receiver. + * + * RU: Команды могут делегировать выполнение любым методам получателя. + */ + void Execute() const override + { + std::cout << "ComplexCommand: Complex stuff should be done by a receiver object.\n"; + this->receiver_->DoSomething(this->a_); + this->receiver_->DoSomethingElse(this->b_); + } +}; + +/** + * EN: The Invoker is associated with one or several commands. It sends a + * request to the command. + * + * RU: Отправитель связан с одной или несколькими командами. Он отправляет + * запрос команде. + */ +class Invoker +{ + /** + * @var Command + */ +private: + Command *on_start_; + /** + * @var Command + */ + Command *on_finish_; + /** + * EN: Initialize commands. + * + * RU: Инициализация команд. + */ +public: + ~Invoker() + { + delete on_start_; + delete on_finish_; + } + + void SetOnStart(Command *command) + { + this->on_start_ = command; + } + void SetOnFinish(Command *command) + { + this->on_finish_ = command; + } + /** + * EN: The Invoker does not depend on concrete command or receiver classes. + * The Invoker passes a request to a receiver indirectly, by executing a + * command. + * + * RU: Отправитель не зависит от классов конкретных команд и получателей. + * Отправитель передаёт запрос получателю косвенно, выполняя команду. + */ + void DoSomethingImportant() + { + std::cout << "Invoker: Does anybody want something done before I begin?\n"; + if (this->on_start_) + { + this->on_start_->Execute(); + } + std::cout << "Invoker: ...doing something really important...\n"; + std::cout << "Invoker: Does anybody want something done after I finish?\n"; + if (this->on_finish_) + { + this->on_finish_->Execute(); + } + } +}; +/** + * EN: The client code can parameterize an invoker with any commands. + * + * RU: Клиентский код может параметризовать отправителя любыми командами. + */ + +int main() +{ + Invoker *invoker = new Invoker; + invoker->SetOnStart(new SimpleCommand("Say Hi!")); + Receiver *receiver = new Receiver; + invoker->SetOnFinish(new ComplexCommand(receiver, "Send email", "Save report")); + invoker->DoSomethingImportant(); + + delete invoker; + delete receiver; + + return 0; +} From 13e81721cfeea7d0d3513171ad0157e2b75a26ae Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Sat, 19 Oct 2019 16:04:24 -0500 Subject: [PATCH 28/36] Iterator design pattern --- src/Iterator/Conceptual/Output.txt | 15 +++ src/Iterator/Conceptual/main.cc | 148 +++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 src/Iterator/Conceptual/Output.txt create mode 100644 src/Iterator/Conceptual/main.cc diff --git a/src/Iterator/Conceptual/Output.txt b/src/Iterator/Conceptual/Output.txt new file mode 100644 index 0000000..f22b4fa --- /dev/null +++ b/src/Iterator/Conceptual/Output.txt @@ -0,0 +1,15 @@ +________________Iterator with int______________________________________ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +________________Iterator with custom Class______________________________ +100 +1000 +10000 \ No newline at end of file diff --git a/src/Iterator/Conceptual/main.cc b/src/Iterator/Conceptual/main.cc new file mode 100644 index 0000000..f15b74b --- /dev/null +++ b/src/Iterator/Conceptual/main.cc @@ -0,0 +1,148 @@ +/** + * EN: Iterator Design Pattern + * + * Intent: Lets you traverse elements of a collection without exposing its + * underlying representation (list, stack, tree, etc.). + * + * RU: Паттерн Итератор + * + * Назначение: Даёт возможность последовательно обходить элементы составных + * объектов, не раскрывая их внутреннего представления. + */ + +#include +#include +#include + +/** + * EN: C++ has its own implementation of iterator that works with + * a different generics containers defined by the standard library. + * + * RU: + */ + +template +class Iterator +{ +public: + typedef typename std::vector::iterator iter_type; + Iterator(U *p_data, bool reverse = false) : m_p_data_(p_data) + { + m_it_ = m_p_data_->m_data_.begin(); + } + + void First() + { + m_it_ = m_p_data_->m_data_.begin(); + } + + void Next() + { + m_it_++; + } + + bool IsDone() + { + return (m_it_ == m_p_data_->m_data_.end()); + } + + iter_type Current() + { + return m_it_; + } + +private: + U *m_p_data_; + iter_type m_it_; +}; + +/** + * EN: Generic Collections/Containers provides one or several methods for retrieving fresh + * iterator instances, compatible with the collection class. + * + * RU: Конкретные Коллекции предоставляют один или несколько методов для + * получения новых экземпляров итератора, совместимых с классом коллекции. + */ + +template +class Container +{ + friend class Iterator; + +public: + void Add(T a) + { + m_data_.push_back(a); + } + + Iterator *CreateIterator() + { + return new Iterator(this); + } + +private: + std::vector m_data_; +}; + +class Data +{ +public: + Data(int a = 0) : m_data_(a) {} + + void set_data(int a) + { + m_data_ = a; + } + + int data() + { + return m_data_; + } + +private: + int m_data_; +}; + +/** + * EN: The client code may or may not know about the Concrete Iterator or + * Collection classes, for this implementation the container is generic so you + * can used with an int or with a custom class. + * + * RU: + */ +void ClientCode() +{ + std::cout << "________________Iterator with int______________________________________" << std::endl; + Container cont; + + for (int i = 0; i < 10; i++) + { + cont.Add(i); + } + + Iterator> *it = cont.CreateIterator(); + for (it->First(); !it->IsDone(); it->Next()) + { + std::cout << *it->Current() << std::endl; + } + + Container cont2; + Data a(100), b(1000), c(10000); + cont2.Add(a); + cont2.Add(b); + cont2.Add(c); + + std::cout << "________________Iterator with custom Class______________________________" << std::endl; + Iterator> *it2 = cont2.CreateIterator(); + for (it2->First(); !it2->IsDone(); it2->Next()) + { + std::cout << it2->Current()->data() << std::endl; + } +} + +int main() +{ + + ClientCode(); + return 0; +} \ No newline at end of file From 80889d325c46468d3fef359d3f7abd05b08d2d36 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Sat, 19 Oct 2019 16:53:23 -0500 Subject: [PATCH 29/36] Mediator design pattern --- src/Mediator/Conceptual/Output.txt | 10 ++ src/Mediator/Conceptual/main.cc | 155 +++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 src/Mediator/Conceptual/Output.txt create mode 100644 src/Mediator/Conceptual/main.cc diff --git a/src/Mediator/Conceptual/Output.txt b/src/Mediator/Conceptual/Output.txt new file mode 100644 index 0000000..4f8a003 --- /dev/null +++ b/src/Mediator/Conceptual/Output.txt @@ -0,0 +1,10 @@ +Client triggers operation A. +Component 1 does A. +Mediator reacts on A and triggers following operations: +Component 2 does C. + +Client triggers operation D. +Component 2 does D. +Mediator reacts on D and triggers following operations: +Component 1 does B. +Component 2 does C. \ No newline at end of file diff --git a/src/Mediator/Conceptual/main.cc b/src/Mediator/Conceptual/main.cc new file mode 100644 index 0000000..b0437cb --- /dev/null +++ b/src/Mediator/Conceptual/main.cc @@ -0,0 +1,155 @@ + +#include +#include +/** + * EN: Mediator Design Pattern + * + * Intent: Lets you reduce chaotic dependencies between objects. The pattern + * restricts direct communications between the objects and forces them to + * collaborate only via a mediator object. + * + * RU: Паттерн Посредник + * + * Назначение: Позволяет уменьшить связанность множества классов между собой, + * благодаря перемещению этих связей в один класс-посредник. + */ + +/** + * EN: The Mediator interface declares a method used by components to notify the + * mediator about various events. The Mediator may react to these events and + * pass the execution to other components. + * + * RU: Интерфейс Посредника предоставляет метод, используемый компонентами для + * уведомления посредника о различных событиях. Посредник может реагировать на + * эти события и передавать исполнение другим компонентам. + */ +class BaseComponent; +class Mediator +{ +public: + virtual void Notify(BaseComponent *sender, std::string event) const = 0; +}; + +/** + * EN: The Base Component provides the basic functionality of storing a + * mediator's instance inside component objects. + * + * RU: Базовый Компонент обеспечивает базовую функциональность хранения + * экземпляра посредника внутри объектов компонентов. + */ +class BaseComponent +{ +protected: + Mediator *mediator_; + +public: + BaseComponent(Mediator *mediator = nullptr) : mediator_(mediator) + { + } + void set_mediator(Mediator *mediator) + { + this->mediator_ = mediator; + } +}; + +/** + * EN: Concrete Components implement various functionality. They don't depend on + * other components. They also don't depend on any concrete mediator classes. + * + * RU: Конкретные Компоненты реализуют различную функциональность. Они не + * зависят от других компонентов. Они также не зависят от каких-либо конкретных + * классов посредников. + */ +class Component1 : public BaseComponent +{ +public: + void DoA() + { + std::cout << "Component 1 does A.\n"; + this->mediator_->Notify(this, "A"); + } + void DoB() + { + std::cout << "Component 1 does B.\n"; + this->mediator_->Notify(this, "B"); + } +}; + +class Component2 : public BaseComponent +{ +public: + void DoC() + { + std::cout << "Component 2 does C.\n"; + this->mediator_->Notify(this, "C"); + } + void DoD() + { + std::cout << "Component 2 does D.\n"; + this->mediator_->Notify(this, "D"); + } +}; + +/** + * EN: Concrete Mediators implement cooperative behavior by coordinating several + * components. + * + * RU: Конкретные Посредники реализуют совместное поведение, координируя + * отдельные компоненты. + */ +class ConcreteMediator : public Mediator +{ +private: + Component1 *component1_; + Component2 *component2_; + +public: + ConcreteMediator(Component1 *c1, Component2 *c2) : component1_(c1), component2_(c2) + { + + this->component1_->set_mediator(this); + this->component2_->set_mediator(this); + } + void Notify(BaseComponent *sender, std::string event) const override + { + if (event == "A") + { + std::cout << "Mediator reacts on A and triggers following operations:\n"; + this->component2_->DoC(); + } + if (event == "D") + { + std::cout << "Mediator reacts on D and triggers following operations:\n"; + this->component1_->DoB(); + this->component2_->DoC(); + } + } +}; + +/** + * EN: The client code. + * + * RU: Клиентский код. + */ + +void ClientCode() +{ + Component1 *c1 = new Component1; + Component2 *c2 = new Component2; + ConcreteMediator *mediator = new ConcreteMediator(c1, c2); + std::cout << "Client triggers operation A.\n"; + c1->DoA(); + std::cout << "\n"; + std::cout << "Client triggers operation D.\n"; + c2->DoD(); + + delete c1; + delete c2; + delete mediator; +} + +int main() +{ + ClientCode(); + return 0; +} From ef3dcd764971af9c59933b976c667fbf749bd378 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Sat, 19 Oct 2019 18:15:17 -0500 Subject: [PATCH 30/36] Memento design pattern --- src/Memento/Conceptual/Output.txt | 33 ++++ src/Memento/Conceptual/main.cc | 253 ++++++++++++++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 src/Memento/Conceptual/Output.txt create mode 100644 src/Memento/Conceptual/main.cc diff --git a/src/Memento/Conceptual/Output.txt b/src/Memento/Conceptual/Output.txt new file mode 100644 index 0000000..bd8931b --- /dev/null +++ b/src/Memento/Conceptual/Output.txt @@ -0,0 +1,33 @@ +Originator: My initial state is: Super-duper-super-puper-super. + +Caretaker: Saving Originator's state... +Originator: I'm doing something important. +Originator: and my state has changed to: uOInE8wmckHYPwZS7PtUTwuwZfCIbz + +Caretaker: Saving Originator's state... +Originator: I'm doing something important. +Originator: and my state has changed to: te6RGmykRpbqaWo5MEwjji1fpM1t5D + +Caretaker: Saving Originator's state... +Originator: I'm doing something important. +Originator: and my state has changed to: hX5xWDVljcQ9ydD7StUfbBt5Z7pcSN + +Caretaker: Here's the list of mementos: +Sat Oct 19 18:09:37 2019 + / (Super-dup...) +Sat Oct 19 18:09:37 2019 + / (uOInE8wmc...) +Sat Oct 19 18:09:37 2019 + / (te6RGmykR...) + +Client: Now, let's rollback! + +Caretaker: Restoring state to: Sat Oct 19 18:09:37 2019 + / (te6RGmykR...) +Originator: My state has changed to: te6RGmykRpbqaWo5MEwjji1fpM1t5D + +Client: Once more! + +Caretaker: Restoring state to: Sat Oct 19 18:09:37 2019 + / (uOInE8wmc...) +Originator: My state has changed to: uOInE8wmckHYPwZS7PtUTwuwZfCIbz \ No newline at end of file diff --git a/src/Memento/Conceptual/main.cc b/src/Memento/Conceptual/main.cc new file mode 100644 index 0000000..018c372 --- /dev/null +++ b/src/Memento/Conceptual/main.cc @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include + +/** + * EN: Memento Design Pattern + * + * Intent: Lets you save and restore the previous state of an object without + * revealing the details of its implementation. + * + * RU: Паттерн Снимок + * + * Назначение: Фиксирует и восстанавливает внутреннее состояние объекта таким + * образом, чтобы в дальнейшем объект можно было восстановить в этом состоянии + * без нарушения инкапсуляции. + */ + +/** + * EN: The Memento interface provides a way to retrieve the memento's metadata, + * such as creation date or name. However, it doesn't expose the Originator's + * state. + * + * RU: Интерфейс Снимка предоставляет способ извлечения метаданных снимка, таких + * как дата создания или название. Однако он не раскрывает состояние Создателя. + */ +class Memento +{ +public: + virtual std::string GetName() const = 0; + virtual std::string date() const = 0; + virtual std::string state() const = 0; +}; + +/** + * EN: The Concrete Memento contains the infrastructure for storing the + * Originator's state. + * + * RU: Конкретный снимок содержит инфраструктуру для хранения состояния + * Создателя. + */ +class ConcreteMemento : public Memento +{ +private: + std::string state_; + std::string date_; + +public: + ConcreteMemento(std::string state) : state_(state) + { + this->state_ = state; + std::time_t now = std::time(0); + this->date_ = std::ctime(&now); + } + /** + * EN: The Originator uses this method when restoring its state. + * + * RU: Создатель использует этот метод, когда восстанавливает своё + * состояние. + */ + std::string state() const override + { + return this->state_; + } + /** + * EN: The rest of the methods are used by the Caretaker to display + * metadata. + * + * RU: Остальные методы используются Опекуном для отображения метаданных. + */ + std::string GetName() const override + { + return this->date_ + " / (" + this->state_.substr(0, 9) + "...)"; + } + std::string date() const override + { + return this->date_; + } +}; + +/** + * EN: The Originator holds some important state that may change over time. It + * also defines a method for saving the state inside a memento and another + * method for restoring the state from it. + * + * RU: Создатель содержит некоторое важное состояние, которое может со временем + * меняться. Он также объявляет метод сохранения состояния внутри снимка и метод + * восстановления состояния из него. + */ +class Originator +{ + /** + * EN: @var string For the sake of simplicity, the originator's state is + * stored inside a single variable. + * + * RU: @var string Для удобства состояние создателя хранится внутри одной + * переменной. + */ +private: + std::string state_; + + std::string GenerateRandomString(int length = 10) + { + const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + int stringLength = sizeof(alphanum) - 1; + + std::string random_string; + for (int i = 0; i < length; i++) + { + random_string += alphanum[std::rand() % stringLength]; + } + return random_string; + } + +public: + Originator(std::string state) : state_(state) + { + std::cout << "Originator: My initial state is: " << this->state_ << "\n"; + } + /** + * EN: The Originator's business logic may affect its internal state. + * Therefore, the client should backup the state before launching methods of + * the business logic via the save() method. + * + * RU: Бизнес-логика Создателя может повлиять на его внутреннее состояние. + * Поэтому клиент должен выполнить резервное копирование состояния с помощью + * метода save перед запуском методов бизнес-логики. + */ + void DoSomething() + { + std::cout << "Originator: I'm doing something important.\n"; + this->state_ = this->GenerateRandomString(30); + std::cout << "Originator: and my state has changed to: " << this->state_ << "\n"; + } + + /** + * EN: Saves the current state inside a memento. + * + * RU: Сохраняет текущее состояние внутри снимка. + */ + Memento *Save() + { + return new ConcreteMemento(this->state_); + } + /** + * EN: Restores the Originator's state from a memento object. + * + * RU: Восстанавливает состояние Создателя из объекта снимка. + */ + void Restore(Memento *memento) + { + this->state_ = memento->state(); + std::cout << "Originator: My state has changed to: " << this->state_ << "\n"; + } +}; + +/** + * EN: The Caretaker doesn't depend on the Concrete Memento class. Therefore, it + * doesn't have access to the originator's state, stored inside the memento. It + * works with all mementos via the base Memento interface. + * + * RU: Опекун не зависит от класса Конкретного Снимка. Таким образом, он не + * имеет доступа к состоянию создателя, хранящемуся внутри снимка. Он работает + * со всеми снимками через базовый интерфейс Снимка. + */ +class Caretaker +{ + /** + * @var Memento[] + */ +private: + std::vector mementos_; + + /** + * @var Originator + */ + Originator *originator_; + +public: + Caretaker(Originator *originator) : originator_(originator) + { + this->originator_ = originator; + } + + void Backup() + { + std::cout << "\nCaretaker: Saving Originator's state...\n"; + this->mementos_.push_back(this->originator_->Save()); + } + void Undo() + { + if (!this->mementos_.size()) + { + return; + } + Memento *memento = this->mementos_.back(); + this->mementos_.pop_back(); + std::cout << "Caretaker: Restoring state to: " << memento->GetName() << "\n"; + try + { + this->originator_->Restore(memento); + } + catch (...) + { + this->Undo(); + } + } + void ShowHistory() const + { + std::cout << "Caretaker: Here's the list of mementos:\n"; + for (Memento *memento : this->mementos_) + { + std::cout << memento->GetName() << "\n"; + } + } +}; +/** + * EN: Client code. + * + * RU: Клиентский код. + */ + +void ClientCode() +{ + Originator *originator = new Originator("Super-duper-super-puper-super."); + Caretaker *caretaker = new Caretaker(originator); + caretaker->Backup(); + originator->DoSomething(); + caretaker->Backup(); + originator->DoSomething(); + caretaker->Backup(); + originator->DoSomething(); + std::cout << "\n"; + caretaker->ShowHistory(); + std::cout << "\nClient: Now, let's rollback!\n\n"; + caretaker->Undo(); + std::cout << "\nClient: Once more!\n\n"; + caretaker->Undo(); + + delete originator; + delete caretaker; +} + +int main() +{ + std::srand(static_cast(std::time(NULL))); + ClientCode(); + return 0; +} \ No newline at end of file From 3534216b81cca635c4b06bd8e6c712fe191b3a69 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Thu, 24 Oct 2019 19:06:38 -0500 Subject: [PATCH 31/36] Observer design pattern --- src/Observer/Conceptual/Output.txt | 27 ++++ src/Observer/Conceptual/main.cc | 194 +++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 src/Observer/Conceptual/Output.txt create mode 100644 src/Observer/Conceptual/main.cc diff --git a/src/Observer/Conceptual/Output.txt b/src/Observer/Conceptual/Output.txt new file mode 100644 index 0000000..a246c18 --- /dev/null +++ b/src/Observer/Conceptual/Output.txt @@ -0,0 +1,27 @@ +Hi, I'm the Observer "1". +Hi, I'm the Observer "2". +Hi, I'm the Observer "3". +There are 3 observers in the list. +Observer "1": a new message is available --> Hello World! :D +Observer "2": a new message is available --> Hello World! :D +Observer "3": a new message is available --> Hello World! :D +Observer "3" removed from the list. +There are 2 observers in the list. +Observer "1": a new message is available --> The weather is hot today! :p +Observer "2": a new message is available --> The weather is hot today! :p +Hi, I'm the Observer "4". +Observer "2" removed from the list. +Hi, I'm the Observer "5". +There are 3 observers in the list. +Observer "1": a new message is available --> My new car is great! ;) +Observer "4": a new message is available --> My new car is great! ;) +Observer "5": a new message is available --> My new car is great! ;) +Observer "5" removed from the list. +Observer "4" removed from the list. +Observer "1" removed from the list. +Goodbye, I was the Observer "5". +Goodbye, I was the Observer "4". +Goodbye, I was the Observer "3". +Goodbye, I was the Observer "2". +Goodbye, I was the Observer "1". +Goodbye, I was the Subject. \ No newline at end of file diff --git a/src/Observer/Conceptual/main.cc b/src/Observer/Conceptual/main.cc new file mode 100644 index 0000000..c013463 --- /dev/null +++ b/src/Observer/Conceptual/main.cc @@ -0,0 +1,194 @@ +/** + * EN: Observer Design Pattern + * + * Intent: Lets you define a subscription mechanism to notify multiple objects + * about any events that happen to the object they're observing. + * + * Note that there's a lot of different terms with similar meaning associated + * with this pattern. Just remember that the Subject is also called the + * Publisher and the Observer is often called the Subscriber and vice versa. + * Also the verbs "observe", "listen" or "track" usually mean the same thing. + * + * RU: Паттерн Наблюдатель + * + * Назначение: Создаёт механизм подписки, позволяющий одним объектам следить и + * реагировать на события, происходящие в других объектах. + * + * Обратите внимание, что существует множество различных терминов с похожими + * значениями, связанных с этим паттерном. Просто помните, что Субъекта также + * называют Издателем, а Наблюдателя часто называют Подписчиком и наоборот. + * Также глаголы «наблюдать», «слушать» или «отслеживать» обычно означают одно и + * то же. + */ + +#include +#include +#include + +class IObserver +{ + +public: + virtual ~IObserver(){}; + virtual void Update(const std::string &message_from_subject) = 0; +}; + +class ISubject +{ +public: + virtual ~ISubject(){}; + virtual void Attach(IObserver *observer) = 0; + virtual void Detach(IObserver *observer) = 0; + virtual void Notify() = 0; +}; + +/** + * EN: The Subject owns some important state and notifies observers when the + * state changes. + * + * RU: Издатель владеет некоторым важным состоянием и оповещает наблюдателей о + * его изменениях. + */ + +class Subject : public ISubject +{ + +public: + virtual ~Subject() + { + std::cout << "Goodbye, I was the Subject.\n"; + } + + /** + * EN: The subscription management methods. + * + * RU: Методы управления подпиской. + */ + void Attach(IObserver *observer) override + { + list_observer_.push_back(observer); + } + void Detach(IObserver *observer) override + { + list_observer_.remove(observer); + } + void Notify() override + { + std::list::iterator iterator = list_observer_.begin(); + HowManyObserver(); + while (iterator != list_observer_.end()) + { + (*iterator)->Update(message_); + ++iterator; + } + } + + void CreateMessage(std::string message = "Empty") + { + this->message_ = message; + Notify(); + } + void HowManyObserver() + { + std::cout << "There are " << list_observer_.size() << " observers in the list.\n"; + } + + /** + * EN: Usually, the subscription logic is only a fraction of what a Subject + * can really do. Subjects commonly hold some important business logic, that + * triggers a notification method whenever something important is about to + * happen (or after it). + * + * RU: Обычно логика подписки – только часть того, что делает Издатель. + * Издатели часто содержат некоторую важную бизнес-логику, которая запускает + * метод уведомления всякий раз, когда должно произойти что-то важное (или + * после этого). + */ + void SomeBusinessLogic() + { + this->message_ = "change message message"; + Notify(); + std::cout << "I'm about to do some thing important\n"; + } + +private: + std::list list_observer_; + std::string message_; +}; + +class Observer : public IObserver +{ + +public: + Observer(Subject &subject) : subject_(subject) + { + this->subject_.Attach(this); + std::cout << "Hi, I'm the Observer \"" << ++Observer::static_number_ << "\".\n"; + this->number_ = Observer::static_number_; + } + virtual ~Observer() + { + std::cout << "Goodbye, I was the Observer \"" << this->number_ << "\".\n"; + } + + void Update(const std::string &message_from_subject) override + { + message_from_subject_ = message_from_subject; + PrintInfo(); + } + void RemoveMeFromTheList() + { + subject_.Detach(this); + std::cout << "Observer \"" << number_ << "\" removed from the list.\n"; + } + void PrintInfo() + { + std::cout << "Observer \"" << this->number_ << "\": a new message is available --> " << this->message_from_subject_ << "\n"; + } + +private: + std::string message_from_subject_; + Subject &subject_; + static int static_number_; + int number_; +}; + +int Observer::static_number_ = 0; + +void ClientCode() +{ + Subject *subject = new Subject; + Observer *observer1 = new Observer(*subject); + Observer *observer2 = new Observer(*subject); + Observer *observer3 = new Observer(*subject); + Observer *observer4; + Observer *observer5; + + subject->CreateMessage("Hello World! :D"); + observer3->RemoveMeFromTheList(); + + subject->CreateMessage("The weather is hot today! :p"); + observer4 = new Observer(*subject); + + observer2->RemoveMeFromTheList(); + observer5 = new Observer(*subject); + + subject->CreateMessage("My new car is great! ;)"); + observer5->RemoveMeFromTheList(); + + observer4->RemoveMeFromTheList(); + observer1->RemoveMeFromTheList(); + + delete observer5; + delete observer4; + delete observer3; + delete observer2; + delete observer1; + delete subject; +} + +int main() +{ + ClientCode(); + return 0; +} From 63cb7d4fc58ed870192581c3f303ab68137ca480 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Sat, 26 Oct 2019 17:20:39 -0500 Subject: [PATCH 32/36] State design pattern --- src/State/Conceptual/Output.txt | 15 +++ src/State/Conceptual/main.cc | 170 ++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 src/State/Conceptual/Output.txt create mode 100644 src/State/Conceptual/main.cc diff --git a/src/State/Conceptual/Output.txt b/src/State/Conceptual/Output.txt new file mode 100644 index 0000000..f03595d --- /dev/null +++ b/src/State/Conceptual/Output.txt @@ -0,0 +1,15 @@ +Context: Transition to 14ConcreteStateA. +ConcreteStateA handles request1. +ConcreteStateA wants to change the state of the context. +Context: Transition to 14ConcreteStateB. +ConcreteStateB handles request2. +ConcreteStateB wants to change the state of the context. +Context: Transition to 14ConcreteStateA. + +Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateA. +ConcreteStateA handles request1. +ConcreteStateA wants to change the state of the context. +Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateB. +ConcreteStateB handles request2. +ConcreteStateB wants to change the state of the context. +Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateA. \ No newline at end of file diff --git a/src/State/Conceptual/main.cc b/src/State/Conceptual/main.cc new file mode 100644 index 0000000..2f3d8bc --- /dev/null +++ b/src/State/Conceptual/main.cc @@ -0,0 +1,170 @@ +#include +#include +/** + * EN: State Design Pattern + * + * Intent: Lets an object alter its behavior when its internal state changes. It + * appears as if the object changed its class. + * + * RU: Паттерн Состояние + * + * Назначение: Позволяет объектам менять поведение в зависимости от своего + * состояния. Извне создаётся впечатление, что изменился класс объекта. + */ + +/** + * EN: The base State class declares methods that all Concrete State should + * implement and also provides a backreference to the Context object, associated + * with the State. This backreference can be used by States to transition the + * Context to another State. + * + * RU: Базовый класс Состояния объявляет методы, которые должны реализовать все + * Конкретные Состояния, а также предоставляет обратную ссылку на объект + * Контекст, связанный с Состоянием. Эта обратная ссылка может использоваться + * Состояниями для передачи Контекста другому Состоянию. + */ + +class Context; + +class State +{ + /** + * @var Context + */ +protected: + Context *context_; + +public: + virtual ~State() + { + } + + void set_context(Context *context) + { + this->context_ = context; + } + + virtual void Handle1() = 0; + virtual void Handle2() = 0; +}; + +/** + * EN: The Context defines the interface of interest to clients. It also + * maintains a reference to an instance of a State subclass, which represents + * the current state of the Context. + * + * RU: Контекст определяет интерфейс, представляющий интерес для клиентов. Он + * также хранит ссылку на экземпляр подкласса Состояния, который отображает + * текущее состояние Контекста. + */ +class Context +{ + /** + * EN: @var State A reference to the current state of the Context. + * + * RU: @var State Ссылка на текущее состояние Контекста. + */ +private: + State *state_; + +public: + Context(State *state) : state_(nullptr) + { + this->TransitionTo(state); + } + ~Context() + { + delete state_; + } + /** + * EN: The Context allows changing the State object at runtime. + * + * RU: Контекст позволяет изменять объект Состояния во время выполнения. + */ + void TransitionTo(State *state) + { + std::cout << "Context: Transition to " << typeid(*state).name() << ".\n"; + if (this->state_ != nullptr) + delete this->state_; + this->state_ = state; + this->state_->set_context(this); + } + /** + * EN: The Context delegates part of its behavior to the current State + * object. + * + * RU: Контекст делегирует часть своего поведения текущему объекту + * Состояния. + */ + void Request1() + { + this->state_->Handle1(); + } + void Request2() + { + this->state_->Handle2(); + } +}; + +/** + * EN: Concrete States implement various behaviors, associated with a state of + * the Context. + * + * RU: Конкретные Состояния реализуют различные модели поведения, связанные с + * состоянием Контекста. + */ + +class ConcreteStateA : public State +{ +public: + void Handle1() override; + + void Handle2() override + { + std::cout << "ConcreteStateA handles request2.\n"; + } +}; + +class ConcreteStateB : public State +{ +public: + void Handle1() override + { + std::cout << "ConcreteStateB handles request1.\n"; + } + void Handle2() override + { + std::cout << "ConcreteStateB handles request2.\n"; + std::cout << "ConcreteStateB wants to change the state of the context.\n"; + this->context_->TransitionTo(new ConcreteStateA); + } +}; + +void ConcreteStateA::Handle1() +{ + { + std::cout << "ConcreteStateA handles request1.\n"; + std::cout << "ConcreteStateA wants to change the state of the context.\n"; + + this->context_->TransitionTo(new ConcreteStateB); + } +} + +/** + * EN: The client code. + * + * RU: Клиентский код. + */ +void ClientCode() +{ + Context *context = new Context(new ConcreteStateA); + context->Request1(); + context->Request2(); + delete context; +} + +int main() +{ + ClientCode(); + return 0; +} From f5b612dfc62d657cfe4076712caa337ef754048f Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Sat, 26 Oct 2019 17:23:37 -0500 Subject: [PATCH 33/36] add Output --- src/State/Conceptual/Output.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/State/Conceptual/Output.txt b/src/State/Conceptual/Output.txt index f03595d..07171eb 100644 --- a/src/State/Conceptual/Output.txt +++ b/src/State/Conceptual/Output.txt @@ -6,10 +6,3 @@ ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to 14ConcreteStateA. -Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateA. -ConcreteStateA handles request1. -ConcreteStateA wants to change the state of the context. -Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateB. -ConcreteStateB handles request2. -ConcreteStateB wants to change the state of the context. -Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateA. \ No newline at end of file From 83de41d3a5da88a96c9f7f587945227fd2c7c3e2 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Sat, 26 Oct 2019 18:39:45 -0500 Subject: [PATCH 34/36] Strategy Pattern --- src/Strategy/Conceptual/Output.txt | 9 ++ src/Strategy/Conceptual/main.cc | 166 +++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 src/Strategy/Conceptual/Output.txt create mode 100644 src/Strategy/Conceptual/main.cc diff --git a/src/Strategy/Conceptual/Output.txt b/src/Strategy/Conceptual/Output.txt new file mode 100644 index 0000000..2bf117e --- /dev/null +++ b/src/Strategy/Conceptual/Output.txt @@ -0,0 +1,9 @@ +Client: Strategy is set to normal sorting. +Context: Sorting data using the strategy (not sure how it'll do it) +abcde + +Client: Strategy is set to reverse sorting. +Context: Sorting data using the strategy (not sure how it'll do it) +edcba + + diff --git a/src/Strategy/Conceptual/main.cc b/src/Strategy/Conceptual/main.cc new file mode 100644 index 0000000..5d5a403 --- /dev/null +++ b/src/Strategy/Conceptual/main.cc @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +/** + * EN: Strategy Design Pattern + * + * Intent: Lets you define a family of algorithms, put each of them into a + * separate class, and make their objects interchangeable. + * + * RU: Паттерн Стратегия + * + * Назначение: Определяет семейство схожих алгоритмов и помещает каждый из них в + * собственный класс, после чего алгоритмы можно взаимозаменять прямо во время + * исполнения программы. + */ + +/** + * EN: The Strategy interface declares operations common to all supported + * versions of some algorithm. + * + * The Context uses this interface to call the algorithm defined by Concrete + * Strategies. + * + * RU: Интерфейс Стратегии объявляет операции, общие для всех поддерживаемых + * версий некоторого алгоритма. + * + * Контекст использует этот интерфейс для вызова алгоритма, определённого + * Конкретными Стратегиями. + */ +class Strategy +{ +public: + virtual ~Strategy() {} + virtual std::string DoAlgorithm(const std::vector &data) const = 0; +}; + +/** + * EN: The Context defines the interface of interest to clients. + * + * RU: Контекст определяет интерфейс, представляющий интерес для клиентов. + */ + +class Context +{ + /** + * EN: @var Strategy The Context maintains a reference to one of the + * Strategy objects. The Context does not know the concrete class of a + * strategy. It should work with all strategies via the Strategy interface. + * + * RU: @var Strategy Контекст хранит ссылку на один из объектов Стратегии. + * Контекст не знает конкретного класса стратегии. Он должен работать со + * всеми стратегиями через интерфейс Стратегии. + */ +private: + Strategy *strategy_; + /** + * + * EN: Usually, the Context accepts a strategy through the constructor, but + * also provides a setter to change it at runtime. + * + * RU: Обычно Контекст принимает стратегию через конструктор, а также + * предоставляет сеттер для её изменения во время выполнения. + */ +public: + Context(Strategy *strategy = nullptr) : strategy_(strategy) + { + } + ~Context() + { + delete this->strategy_; + } + /** + * EN: Usually, the Context allows replacing a Strategy object at runtime. + * + * RU: Обычно Контекст позволяет заменить объект Стратегии во время + * выполнения. + */ + void set_strategy(Strategy *strategy) + { + delete this->strategy_; + this->strategy_ = strategy; + } + /** + * EN: The Context delegates some work to the Strategy object instead of + * implementing +multiple versions of the algorithm on its own. + * + * RU: Вместо того, чтобы самостоятельно реализовывать множественные версии + * алгоритма, Контекст делегирует некоторую работу объекту Стратегии. + */ + void DoSomeBusinessLogic() const + { + // ... + std::cout << "Context: Sorting data using the strategy (not sure how it'll do it)\n"; + std::string result = this->strategy_->DoAlgorithm(std::vector{"a", "e", "c", "b", "d"}); + std::cout << result << "\n"; + // ... + } +}; + +/** + * EN: Concrete Strategies implement the algorithm while following the base + * Strategy interface. The interface makes them interchangeable in the Context. + * + * RU: Конкретные Стратегии реализуют алгоритм, следуя базовому интерфейсу + * Стратегии. Этот интерфейс делает их взаимозаменяемыми в Контексте. + */ +class ConcreteStrategyA : public Strategy +{ +public: + std::string DoAlgorithm(const std::vector &data) const override + { + std::string result; + std::for_each(std::begin(data), std::end(data), [&result](const std::string &letter) { + result += letter; + }); + std::sort(std::begin(result), std::end(result)); + + return result; + } +}; +class ConcreteStrategyB : public Strategy +{ + std::string DoAlgorithm(const std::vector &data) const override + { + std::string result; + std::for_each(std::begin(data), std::end(data), [&result](const std::string &letter) { + result += letter; + }); + std::sort(std::begin(result), std::end(result)); + for (int i = 0; i < result.size() / 2; i++) + { + std::swap(result[i], result[result.size() - i - 1]); + } + + return result; + } +}; +/** + * EN: The client code picks a concrete strategy and passes it to the context. + * The client should be aware of the differences between strategies in order to + * make the right choice. + * + * RU: Клиентский код выбирает конкретную стратегию и передаёт её в контекст. + * Клиент должен знать о различиях между стратегиями, чтобы сделать правильный + * выбор. + */ + +void ClientCode() +{ + Context *context = new Context(new ConcreteStrategyA); + std::cout << "Client: Strategy is set to normal sorting.\n"; + context->DoSomeBusinessLogic(); + std::cout << "\n"; + std::cout << "Client: Strategy is set to reverse sorting.\n"; + context->set_strategy(new ConcreteStrategyB); + context->DoSomeBusinessLogic(); + delete context; +} + +int main() +{ + ClientCode(); + return 0; +} \ No newline at end of file From 9aafd2516d21aeb2eb33baeeaa9a353cb492299e Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Sat, 26 Oct 2019 19:25:30 -0500 Subject: [PATCH 35/36] Template Method Design Pattern --- src/TemplateMethod/Conceptual/Output.txt | 15 +++ src/TemplateMethod/Conceptual/main.cc | 159 +++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 src/TemplateMethod/Conceptual/Output.txt create mode 100644 src/TemplateMethod/Conceptual/main.cc diff --git a/src/TemplateMethod/Conceptual/Output.txt b/src/TemplateMethod/Conceptual/Output.txt new file mode 100644 index 0000000..5b1c985 --- /dev/null +++ b/src/TemplateMethod/Conceptual/Output.txt @@ -0,0 +1,15 @@ +Same client code can work with different subclasses: +AbstractClass says: I am doing the bulk of the work +ConcreteClass1 says: Implemented Operation1 +AbstractClass says: But I let subclasses override some operations +ConcreteClass1 says: Implemented Operation2 +AbstractClass says: But I am doing the bulk of the work anyway + +Same client code can work with different subclasses: +AbstractClass says: I am doing the bulk of the work +ConcreteClass2 says: Implemented Operation1 +AbstractClass says: But I let subclasses override some operations +ConcreteClass2 says: Overridden Hook1 +ConcreteClass2 says: Implemented Operation2 +AbstractClass says: But I am doing the bulk of the work anyway + diff --git a/src/TemplateMethod/Conceptual/main.cc b/src/TemplateMethod/Conceptual/main.cc new file mode 100644 index 0000000..9501c5d --- /dev/null +++ b/src/TemplateMethod/Conceptual/main.cc @@ -0,0 +1,159 @@ +#include + +/** + * EN: Template Method Design Pattern + * + * Intent: Defines the skeleton of an algorithm in the superclass but lets + * subclasses override specific steps of the algorithm without changing its + * structure. + * + * RU: Паттерн Шаблонный метод + * + * Назначение: Определяет общую схему алгоритма, перекладывая реализацию + * некоторых шагов на подклассы. Шаблонный метод позволяет подклассам + * переопределять отдельные шаги алгоритма без изменения структуры алгоритма. + */ +/** + * EN: The Abstract Class defines a template method that contains a skeleton of + * some algorithm, composed of calls to (usually) abstract primitive operations. + * + * Concrete subclasses should implement these operations, but leave the template + * method itself intact. + * + * RU: Абстрактный Класс определяет шаблонный метод, содержащий скелет + * некоторого алгоритма, состоящего из вызовов (обычно) абстрактных примитивных + * операций. + * + * Конкретные подклассы должны реализовать эти операции, но оставить сам + * шаблонный метод без изменений. + */ +class AbstractClass +{ + /** + * EN: The template method defines the skeleton of an algorithm. + * + * RU: Шаблонный метод определяет скелет алгоритма. + */ +public: + void TemplateMethod() const + { + this->BaseOperation1(); + this->RequiredOperations1(); + this->BaseOperation2(); + this->Hook1(); + this->RequiredOperation2(); + this->BaseOperation3(); + this->Hook2(); + } + /** + * EN: These operations already have implementations. + * + * RU: Эти операции уже имеют реализации. + */ +protected: + void BaseOperation1() const + { + std::cout << "AbstractClass says: I am doing the bulk of the work\n"; + } + void BaseOperation2() const + { + std::cout << "AbstractClass says: But I let subclasses override some operations\n"; + } + void BaseOperation3() const + { + std::cout << "AbstractClass says: But I am doing the bulk of the work anyway\n"; + } + /** + * EN: These operations have to be implemented in subclasses. + * + * RU: А эти операции должны быть реализованы в подклассах. + */ + virtual void RequiredOperations1() const = 0; + virtual void RequiredOperation2() const = 0; + /** + * EN: These are "hooks." Subclasses may override them, but it's not + * mandatory since the hooks already have default (but empty) + * implementation. Hooks provide additional extension points in some crucial + * places of the algorithm. + * + * RU: Это «хуки». Подклассы могут переопределять их, но это не обязательно, + * поскольку у хуков уже есть стандартная (но пустая) реализация. Хуки + * предоставляют дополнительные точки расширения в некоторых критических + * местах алгоритма. + */ + virtual void Hook1() const {} + virtual void Hook2() const {} +}; +/** + * EN: Concrete classes have to implement all abstract operations of the base + * class. They can also override some operations with a default implementation. + * + * RU: Конкретные классы должны реализовать все абстрактные операции базового + * класса. Они также могут переопределить некоторые операции с реализацией по + * умолчанию. + */ +class ConcreteClass1 : public AbstractClass +{ +protected: + void RequiredOperations1() const override + { + std::cout << "ConcreteClass1 says: Implemented Operation1\n"; + } + void RequiredOperation2() const override + { + std::cout << "ConcreteClass1 says: Implemented Operation2\n"; + } +}; +/** + * EN: Usually, concrete classes override only a fraction of base class' + * operations. + * + * RU: Обычно конкретные классы переопределяют только часть операций базового + * класса. + */ +class ConcreteClass2 : public AbstractClass +{ +protected: + void RequiredOperations1() const override + { + std::cout << "ConcreteClass2 says: Implemented Operation1\n"; + } + void RequiredOperation2() const override + { + std::cout << "ConcreteClass2 says: Implemented Operation2\n"; + } + void Hook1() const override + { + std::cout << "ConcreteClass2 says: Overridden Hook1\n"; + } +}; +/** + * EN: The client code calls the template method to execute the algorithm. + * Client code does not have to know the concrete class of an object it works + * with, as long as it works with objects through the interface of their base + * class. + * + * RU: Клиентский код вызывает шаблонный метод для выполнения алгоритма. + * Клиентский код не должен знать конкретный класс объекта, с которым работает, + * при условии, что он работает с объектами через интерфейс их базового класса. + */ +void ClientCode(AbstractClass *class_) +{ + // ... + class_->TemplateMethod(); + // ... +} + +int main() +{ + std::cout << "Same client code can work with different subclasses:\n"; + ConcreteClass1 *concreteClass1 = new ConcreteClass1; + ClientCode(concreteClass1); + std::cout << "\n"; + std::cout << "Same client code can work with different subclasses:\n"; + ConcreteClass2 *concreteClass2 = new ConcreteClass2; + ClientCode(concreteClass2); + delete concreteClass1; + delete concreteClass2; + return 0; +} From e6681ce980ab5c557cf5f4686cad08dc07c9b3d4 Mon Sep 17 00:00:00 2001 From: Eder Duran Date: Sun, 27 Oct 2019 21:31:13 -0500 Subject: [PATCH 36/36] Visitor design pattern --- src/Visitor/Conceptual/Output.txt | 8 ++ src/Visitor/Conceptual/main.cc | 188 ++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 src/Visitor/Conceptual/Output.txt create mode 100644 src/Visitor/Conceptual/main.cc diff --git a/src/Visitor/Conceptual/Output.txt b/src/Visitor/Conceptual/Output.txt new file mode 100644 index 0000000..1e110eb --- /dev/null +++ b/src/Visitor/Conceptual/Output.txt @@ -0,0 +1,8 @@ +The client code works with all visitors via the base Visitor interface: +A + ConcreteVisitor1 +B + ConcreteVisitor1 + +It allows the same client code to work with different types of visitors: +A + ConcreteVisitor2 +B + ConcreteVisitor2 + diff --git a/src/Visitor/Conceptual/main.cc b/src/Visitor/Conceptual/main.cc new file mode 100644 index 0000000..307cba5 --- /dev/null +++ b/src/Visitor/Conceptual/main.cc @@ -0,0 +1,188 @@ +#include +#include +#include + +/** + * EN: Visitor Design Pattern + * + * Intent: Lets you separate algorithms from the objects on which they operate. + * + * RU: Паттерн Посетитель + * + * Назначение: Позволяет создавать новые операции, не меняя классы объектов, над + * которыми эти операции могут выполняться. + */ + +/** + * EN: The Visitor Interface declares a set of visiting methods that correspond + * to component classes. The signature of a visiting method allows the visitor + * to identify the exact class of the component that it's dealing with. + * + * RU: Интерфейс Посетителя объявляет набор методов посещения, соответствующих + * классам компонентов. Сигнатура метода посещения позволяет посетителю + * определить конкретный класс компонента, с которым он имеет дело. + */ +class ConcreteComponentA; +class ConcreteComponentB; + +class Visitor +{ +public: + virtual void VisitConcreteComponentA(const ConcreteComponentA *element) const = 0; + virtual void VisitConcreteComponentB(const ConcreteComponentB *element) const = 0; +}; + +/** + * EN: The Component interface declares an `accept` method that should take the + * base visitor interface as an argument. + * + * RU: Интерфейс Компонента объявляет метод accept, который в качестве аргумента + * может получать любой объект, реализующий интерфейс посетителя. + */ + +class Component +{ +public: + virtual ~Component() {} + virtual void Accept(Visitor *visitor) const = 0; +}; + +/** + * EN: Each Concrete Component must implement the `Accept` method in such a way + * that it calls the visitor's method corresponding to the component's class. + * + * RU: Каждый Конкретный Компонент должен реализовать метод accept таким + * образом, чтобы он вызывал метод посетителя, соответствующий классу + * компонента. + */ +class ConcreteComponentA : public Component +{ + /** + * EN: Note that we're calling `visitConcreteComponentA`, which matches the + * current class name. This way we let the visitor know the class of the + * component it works with. + * + * RU: Обратите внимание, мы вызываем visitConcreteComponentA, что + * соответствует названию текущего класса. Таким образом мы позволяем + * посетителю узнать, с каким классом компонента он работает. + */ +public: + void Accept(Visitor *visitor) const override + { + visitor->VisitConcreteComponentA(this); + } + /** + * EN: Concrete Components may have special methods that don't exist in + * their base class or interface. The Visitor is still able to use these + * methods since it's aware of the component's concrete class. + * + * RU: Конкретные Компоненты могут иметь особые методы, не объявленные в их + * базовом классе или интерфейсе. Посетитель всё же может использовать эти + * методы, поскольку он знает о конкретном классе компонента. + */ + std::string ExclusiveMethodOfConcreteComponentA() const + { + return "A"; + } +}; + +class ConcreteComponentB : public Component +{ + /** + * EN: Same here: visitConcreteComponentB => ConcreteComponentB + * + * RU: То же самое здесь: visitConcreteComponentB => ConcreteComponentB + */ +public: + void Accept(Visitor *visitor) const override + { + visitor->VisitConcreteComponentB(this); + } + std::string SpecialMethodOfConcreteComponentB() const + { + return "B"; + } +}; + +/** + * EN: Concrete Visitors implement several versions of the same algorithm, which + * can work with all concrete component classes. + * + * You can experience the biggest benefit of the Visitor pattern when using it + * with a complex object structure, such as a Composite tree. In this case, it + * might be helpful to store some intermediate state of the algorithm while + * executing visitor's methods over various objects of the structure. + * + * RU: Конкретные Посетители реализуют несколько версий одного и того же + * алгоритма, которые могут работать со всеми классами конкретных компонентов. + * + * Максимальную выгоду от паттерна Посетитель вы почувствуете, используя его со + * сложной структурой объектов, такой как дерево Компоновщика. В этом случае + * было бы полезно хранить некоторое промежуточное состояние алгоритма при + * выполнении методов посетителя над различными объектами структуры. + */ +class ConcreteVisitor1 : public Visitor +{ +public: + void VisitConcreteComponentA(const ConcreteComponentA *element) const override + { + std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor1\n"; + } + + void VisitConcreteComponentB(const ConcreteComponentB *element) const override + { + std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor1\n"; + } +}; + +class ConcreteVisitor2 : public Visitor +{ +public: + void VisitConcreteComponentA(const ConcreteComponentA *element) const override + { + std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor2\n"; + } + void VisitConcreteComponentB(const ConcreteComponentB *element) const override + { + std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor2\n"; + } +}; +/** + * EN: The client code can run visitor operations over any set of elements + * without figuring out their concrete classes. The accept operation directs a + * call to the appropriate operation in the visitor object. + * + * RU: Клиентский код может выполнять операции посетителя над любым набором + * элементов, не выясняя их конкретных классов. Операция принятия направляет + * вызов к соответствующей операции в объекте посетителя. + */ +void ClientCode(std::array components, Visitor *visitor) +{ + // ... + for (const Component *comp : components) + { + comp->Accept(visitor); + } + // ... +} + +int main() +{ + std::array components = {new ConcreteComponentA, new ConcreteComponentB}; + std::cout << "The client code works with all visitors via the base Visitor interface:\n"; + ConcreteVisitor1 *visitor1 = new ConcreteVisitor1; + ClientCode(components, visitor1); + std::cout << "\n"; + std::cout << "It allows the same client code to work with different types of visitors:\n"; + ConcreteVisitor2 *visitor2 = new ConcreteVisitor2; + ClientCode(components, visitor2); + + for (const Component *comp : components) + { + delete comp; + } + delete visitor1; + delete visitor2; + + return 0; +}