Basic understanding of design patterns

Posted by sarika on Tue, 28 Dec 2021 14:52:57 +0100

Baidu definition: design mode (Design pattern) is a set of code design experience that is repeatedly used, known by most people, classified and catalogued. The purpose of using design patterns is to reuse code, make code easier to be understood by others and ensure code reliability. There is no doubt that design patterns win more for themselves, others and the system. Design patterns make code preparation truly engineering and Design pattern is the cornerstone of software engineering, just like a brick of a building. Design patterns are divided into three types: creation pattern, structure pattern and behavior pattern.

In fact, the design pattern is applied in combination with a project, not just a program, so the program in this paper just stays at the level of conceptual understanding. There are actually 23 design patterns. This article only introduces the most commonly used dozen

Create pattern
Singleton mode:

Instance method return_ intance object_ The instance object is the only object

#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
class Singleton{
public:
    static Singleton* Instance(){
        if (_instance == nullptr) {
            _mxt.lock();
            if (_instance == nullptr) {
                _instance = new Singleton();
            }

            _mxt.unlock();
        }
        return _instance;
    }

private:
    Singleton(){
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
    Singleton(const Singleton&) = delete;
    Singleton(Singleton &&) = delete;

    static mutex _mxt;
    static Singleton* _instance;
};

Singleton *Singleton::_instance = nullptr;
std::mutex Singleton::_mxt;

void creatSingleton() {
    Singleton* p = Singleton::Instance();
    cout << p << endl;
}

int main() {

    //Singleton *p = Singleton::Instance();

    std::thread t1(creatSingleton);
    std::thread t2(creatSingleton);
    std::thread t3(creatSingleton);
    std::thread t4(creatSingleton);

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    return 0;
}
Factory mode

The premise is that there is a similar product base class that derives multiple product subclasses, and then there must be a factory class that instantiates product subclasses

#include<iostream>
//#include<thread>
#include<mutex>
using namespace std;

class AbstractProduct {
public:
    virtual ~AbstractProduct(){};

    virtual void print() = 0;
};

class  Product1 : public AbstractProduct {
    void print() override {
        cout << "this id product 1" << endl;
    }
};
class  Product2 : public AbstractProduct {
    
    void print() override {
        cout << "this id product 2" << endl;
    }
};

class  Product3 : public AbstractProduct {
    
    void print() override {
        cout << "this id product 3" << endl;
    }
};

//Single case factory. The opposite is the abstract factory pattern, which derives multiple factories from a factory base class
class Factory {
public:
    static Factory* Instance() {

        if (Factory::_instance == nullptr) {
                _mtx.lock();
                if (_instance == nullptr) {
                    _instance = new Factory();
                }
                _mtx.unlock();  
        }
        return _instance;
    }

    AbstractProduct* getProducr(std::string name) {
        if (name == "A") {
            return new Product1;
        } else if (name == "B") {
            return new Product2;
        } else if (name == "C") {
            return new Product3;
        } else {
            return nullptr;
        }
    }

private: 
    Factory(){}
    Factory(const Factory&) = delete;
    Factory(Factory &&) = delete;

    static Factory* _instance;
    static mutex _mtx;

};

Factory* Factory::_instance = nullptr;
std::mutex Factory::_mtx;

int main() {
    AbstractProduct* products[10];
    products[0] = Factory::Instance()->getProducr("A");
    products[1] = Factory::Instance()->getProducr("B");
    products[2] = Factory::Instance()->getProducr("C");
    products[3] = Factory::Instance()->getProducr("A");
    products[4] = Factory::Instance()->getProducr("A");
    products[5] = Factory::Instance()->getProducr("B");
    products[6] = Factory::Instance()->getProducr("C");
    products[7] = Factory::Instance()->getProducr("B");
    products[8] = Factory::Instance()->getProducr("A");
    products[9] = Factory::Instance()->getProducr("E");

    for (auto p : products) {
        if (p) {
            p->print();
        } else {
            cout << "product is nullptr" << endl;
        }
    }
    return 0;
}
Builder pattern

Similar to the factory model, the factory model focuses on creating products, while the builder model focuses on the creation process of products.

Prototype mode

Copy and construct yourself by yourself

Builder and prototype pattern code demonstration:

Realize the automobile production process;

#include<iostream>
#include<shared_mutex>
#include<memory>
using namespace std;

//Factory mode factory
class Car {
public:
	Car() {}

	virtual ~Car(){}
	virtual Car* copy() = 0;
	virtual void setColor(long color) = 0;
	virtual void setEngine(long engine) = 0;
	virtual void setSeat(long seat) = 0;

	virtual void print() {
		cout << "color = " << _color << " engine = " << _engine << " seat = " << _seat << endl;

	}

protected:
	long _color;
	int _seat;
	float _engine;
};

//Factory mode products
class BMW : public Car {
	Car *copy() override {
		return new BMW(*this); 
	}
	
	virtual void setColor(long color) override {
		cout << "BMW set color" << endl;
		this->_color = color;
	}
	virtual void setEngine(long engine) override {
		cout << "BMW set engine" << endl;
		this->_engine = engine;
	}
	virtual void setSeat(long seat) override {
		cout << "BMW set seat" << endl;
		this->_seat = seat;
	}

};

//Factory mode products
class BENZ : public Car {
	Car *copy() override {
		return new BENZ(*this); 
	}
	virtual void setColor(long color) override {
		cout << "BENZ set color" << endl;
		this->_color = color;
	}
	virtual void setEngine(long engine) override {
		cout << "BENZ set engine" << endl;
		this->_engine = engine;
	}
	virtual void setSeat(long seat) override {
		cout << "BENZ set seat" << endl;
		this->_seat = seat;
	}
};

//Factory mode products
class AUDI : public Car {	
	Car *copy() override {
		return new AUDI(*this); 
	}
	virtual void setColor(long color) override {
		cout << "AUDI set color" << endl;
		this->_color = color;
	}
	virtual void setEngine(long engine) override {
		cout << "AUDI set engine" << endl;
		this->_engine = engine;
	}
	virtual void setSeat(long seat) override {
		cout << "AUDI set seat" << endl;
		this->_seat = seat;
	}

};

//Builder in UML
class AbstractBuilder {
public:
	AbstractBuilder(){};
	virtual ~AbstractBuilder(){}

	virtual void buildColor(shared_ptr<Car>) = 0;
	virtual void buildSeat(shared_ptr<Car>) = 0;
	virtual void buildEngine(shared_ptr<Car>) = 0;
	virtual shared_ptr<Car> buildCar() = 0;
};

//ConcreteBuilder in UML
class BMWBuilder : public AbstractBuilder {
public:
	void buildColor(shared_ptr<Car> p) override {
		p->setColor(0x0000ff);
	}

	void buildSeat(shared_ptr<Car> p) override {
		p->setSeat(2);
	}

	void buildEngine(shared_ptr<Car> p) override {
		p->setEngine(3.0f);
	}

	shared_ptr<Car> buildCar() override {
		shared_ptr<Car> p = make_shared<BMW>();

		this->buildColor(p);
		this->buildEngine(p);
		this->buildSeat(p);
		return p;
	}
};

//ConcreteBuilder in UML
class BENZBuild : public AbstractBuilder {
public:
	void buildColor(shared_ptr<Car> p) override {
		p->setColor(0x000000);
	}

	void buildSeat(shared_ptr<Car> p) override {
		p->setSeat(5);
	}

	void buildEngine(shared_ptr<Car> p) override {
		p->setEngine(1.0f);
	}

	shared_ptr<Car> buildCar() override {
		shared_ptr<Car> p = make_shared<BENZ>();

		this->buildEngine(p);
		this->buildSeat(p);
		this->buildColor(p);
		return p;
	}
};

//ConcreteBuilder in UML
class AUDIBuilder : public AbstractBuilder {
public:
	void buildColor(shared_ptr<Car> p) override {
		p->setColor(0x0000ff);
	}

	void buildSeat(shared_ptr<Car> p) override {
		p->setSeat(3);
	}

	void buildEngine(shared_ptr<Car> p) override {
		p->setEngine(4.0f);
	}

	shared_ptr<Car> buildCar() override {
		shared_ptr<Car> p = make_shared<AUDI>();

		this->buildEngine(p);
		this->buildColor(p);
		this->buildSeat(p);
		return p;
	}
};

class Boss {
public:
	Boss(){}
	virtual ~Boss(){
		_builder.reset();
	}

	void setBuilder(shared_ptr<AbstractBuilder> p) {
		_builder = p;
		p.reset();
	}

	shared_ptr<Car> getCar() {
		return _builder ? _builder->buildCar() : nullptr;
	}

private:
	shared_ptr<AbstractBuilder> _builder;
};

int main() {
	shared_ptr<AbstractBuilder> pBuilder[3];
	pBuilder[0] = make_shared<BENZBuild>();
	pBuilder[1] = make_shared<BENZBuild>();
	pBuilder[2] = make_shared<BENZBuild>();

	for (auto p : pBuilder) {
		shared_ptr<Car> pCar = p->buildCar();
		pCar->print();
		
        //Prototype mode
		Car *pCopy = pCar->copy();
		pCopy->print();
	}


cout << "//" << endl;
	shared_ptr<Boss> boss = make_shared<Boss>();
	shared_ptr<BMWBuilder> pp1 = make_shared<BMWBuilder>();
	shared_ptr<BENZBuild> pp2 = make_shared<BENZBuild>();

	boss->setBuilder(pp1);//boss->setBuilder(shared_ptr<BMWBuilder>()).....x
	shared_ptr<Car> p1 = boss->getCar();
	p1->print();

	boss->setBuilder(pp2);
	shared_ptr<Car> p2 = boss->getCar();
	p2->print();

	return 0;	
}
Structural model
Bridging mode

Example: implement the above UML diagram

Bridge the mobile phone class and game class through a game attribute

#include<iostream>
using namespace std;

class Game {
public:
    Game(){}
    virtual ~Game(){}

    virtual void run() = 0;
};

class Phone {
public:
    Phone(){};
    virtual ~Phone(){};

    virtual void installGame(Game *p) = 0;
    virtual void runGame() = 0;
protected:
    Game *_game;//Bridge the mobile phone class and game class through a game attribute

};

class PhoneA : public Phone {
public:
    void installGame(Game *p) override {
        this->_game = p;
    }
    void runGame() override {
        if (this->_game) {
            cout << "Phone start launch game!" << endl;
            this->_game->run();
        } else {
            cout << "Phone not found any game!" << endl;
        }
    }
};

class PhoneB : public Phone {
public:
    void installGame(Game *p) override {
        this->_game = p;
    }
    
    void runGame() override {
        if (this->_game) {
            cout << "Phone start launch game!" << endl;
            this->_game->run();
        } else {
            cout << "Phone not found any game!" << endl;
        }
    }
};

class GameA : public Game{
public:
    void run() override {
        cout << "GameA is starting!" << endl;
    }
};

class GameB : public Game{
public:
    void run() override {
        cout << "GameA is starting!" << endl;
    }
};

int main() {
    Phone *phone1 = new PhoneA();
    Phone *phone2 = new PhoneB();

    Game *game1 = new GameA();
    Game *game2 = new GameB();

    phone1->installGame(game1);
    phone2->installGame(game2);
    
    phone1->runGame();
    phone2->runGame();

    delete phone1;
    delete phone2;

    return 0;
}
Adapter mode

Class Adapter: for example, if the client wants to access the Request method in the Target class, and the specific Request method in the Adaptee class is really to be accessed, there must be an Adapter. The Request method of the Adapter can call the specific Request method in the Adaptee

Object Adapter: for example, if the client wants to access the Request method in the Target class, and the specific Request method in the Adaptee class is really to be accessed, there must be an Adapter. The Adapter inherits the Target class, and the Adaptee class is placed in the Adapter class as an object

#include<iostream>
using namespace std;

//Class implementation that the customer wants
class Target{
public:
    Target(){}

    virtual ~Target(){}

    virtual int request() = 0;
};

//Existing class implementations
class Adaptee {
public:
    Adaptee() {}

    virtual ~Adaptee() {}

    virtual int otherRequest() {
        cout << "Adaptee Run otherRequest!" << endl;
        return 999;
    }
};

//The second existential class implementation
class AAdaptee : public Adaptee {
public:
    AAdaptee() {}

    virtual ~AAdaptee() {}

    int otherRequest() {
        cout << "AAdaptee Run otherRequest!" << endl;
        return 888;
    }
};

//Class adapter, by accessing existing classes, the direct inheritance method is too coupled
class Adapter : public Target, public Adaptee {

public:
    int request() override{
        this->otherRequest();
    }
};

//The object adapter can flexibly bind the objects that need to be adapted by passing the objects of the existing classes, that is, the customer's class can bind which one it wants to bind
class AAdapter : public Target { 
private:
    Adaptee* _adaptee;

public:
    AAdapter() = delete;
    AAdapter(Adaptee *p) : _adaptee(p) {

    }

    virtual ~AAdapter() {
        delete _adaptee;    
    }

    int request() override {
        return this->_adaptee->otherRequest();
    }
};

int main() {
    Adapter *adapter = new Adapter();
    auto ret = adapter->request();
    cout << " ret = " << ret << endl;

    Target *p = new AAdapter(new Adaptee());
    auto i = p->request();
    cout << "ret = " << i << endl;
    
    //In the case of multiple existing classes, the object adapter only needs to pass the existing class. If it is a class adapter, it has to write a class
    Target *pp = new AAdapter(new AAdaptee());
    auto j = pp->request();
    cout << "ret = " << j << endl;

    return 0;
}
Decorator mode

A class has implemented some functions, and some classes implement decoration, content addition or modification functions for the existing class

#include<iostream>
using namespace std;

class AbstractPerson {
public:
    virtual ~AbstractPerson(){}

    virtual void run() = 0;
    virtual void walk() = 0;
};

class Person : public AbstractPerson {
public:
    Person(){}
    ~Person(){}

    void run() override {
        cout << "Person Run!" << endl;
    }

    void walk() override {
        cout << "Person Walk!" << endl;
    }
};

class AbstractDecoratorPerson : public AbstractPerson {
public:
    AbstractDecoratorPerson(AbstractPerson *p) : _person(p){}
    ~AbstractDecoratorPerson(){}

    void run() override {
        cout << " Decorator Person run!" << endl;
    }
    void walk() override {
        cout << " Decorator Person walk!" << endl;
    }

protected:
    AbstractPerson *_person;
};

class DecoratorPersonBlack : public AbstractDecoratorPerson {
public:
    DecoratorPersonBlack(AbstractPerson *p) : AbstractDecoratorPerson(p) {

    }
    ~DecoratorPersonBlack(){}

    void run() override {
        cout << "Black Person running fastly!" << endl;
        _person->run();
        _person->run();
    }
};

class DecoratorPersonOld : public AbstractDecoratorPerson {
public:
    DecoratorPersonOld(AbstractPerson *p) : AbstractDecoratorPerson(p) {

    }
    ~DecoratorPersonOld(){}

    void run() override {
        cout << " old Person cannot run!" << endl;
        this->help();
    }

    void walk() override {
        cout << "Old Person Walk Very Slowly!" << endl;
    }

    void help() {
        cout << " Old Person Need Help" << endl;
    }
};

int main() {
    AbstractPerson *p = new Person();
    p->run();
    p->walk();

    DecoratorPersonOld *p1 = new DecoratorPersonOld(p);
    DecoratorPersonBlack *p2 = new DecoratorPersonBlack(p);

    delete p;
    delete p1;
    delete p2;
    return 0;
}
Appearance mode

When data comes, it needs to be injected into multiple systems. If there is no unified interface, the data must be injected multiple times. Multiple injection of data is likely to lead to an injection failure. If there is a problem on the client, it will lead to a problem on the server. Appearance mode is to provide an injection interface, and the client can call this interface

#include<iostream>
#include<vector>
using namespace std;

class AbstractFaced {
public:
    virtual ~AbstractFaced(){}

    virtual void Register() = 0;
    virtual void Login() = 0;
};

class SystemA : public AbstractFaced {
public:
    SystemA(){}
    virtual ~SystemA(){}

    void Register() override {
        cout << "SystemA Reginster!" << endl;
    }

    void Login() override {
        cout << "SystemA Login!" << endl;
    }
};

class SystemB : public AbstractFaced {
public:
    SystemB(){}
    virtual ~SystemB(){}

    void Register() override {
        cout << "SystemB Reginster!" << endl;
    }

    void Login() override {
        cout << "SystemB Login!" << endl;
    }
};

class Facede : public AbstractFaced {
private:
    vector<AbstractFaced*> systemArray;

public:
    Facede() {
        systemArray.push_back(new SystemA());
        systemArray.push_back(new SystemB());
    }
    ~Facede() {
        for (auto p : systemArray) {
            delete p ;
        }
    }

    void Register() override {
        for (auto p : systemArray) {
            p->Register();
        }
    }

    void Login() override {
        for (auto p : systemArray) {
            p->Login();
        }
    }


};

int main() {

    Facede facede;
    facede.Register();
    facede.Login();
    return 0;
}
Agency mode / entrustment mode

You can access the subject class through the intermediate class Proxy

#include<iostream>
using namespace std;

class Person {
protected:
    Person *_proxy;

public:
    Person(){}
    virtual ~Person(){}

    virtual void rentHouse() = 0;
    virtual void setDelegate(Person *p) {
        _proxy = p;
    }
};

class Proxy : public Person {
public:
    Proxy(){}
    virtual ~Proxy(){}

    void rentHouse() override {
        if (_proxy) {
            cout << "Proxy Need To Rent House!" << endl;
            _proxy->rentHouse();
            cout << "Proxy Need To Charge As Intermidary!" << endl;
        }
    }
};

class Master : public Proxy {
public:
    Master(){}

    virtual ~Master(){}

    void rentHouse() override {
        cout << "Master Need Rent House!" << endl;
    }
};

int main() {
    Person *p = new Master();
    Person *proxy = new Proxy();
    proxy->setDelegate(p);
    proxy->rentHouse();

    delete proxy;
    delete p;
    return 0;
}
Behavioral model
Template approach model

Put the logic / Algorithm in the abstract base class, and define the interface and subclass implementation details that need to be implemented

#include<iostream>
using namespace std;

class factory {
public:
	virtual ~factory() {};

	virtual void buildCar() {
		this->buildA();
		this->buildB();
		this->buildC();
		this->buildD();
		cout << "Build Finised!" << endl;
	}

	virtual void buildA() = 0;
	virtual void buildB() = 0;
	virtual void buildC() = 0;
	virtual void buildD() = 0;
};

class FactoryBMW : public factory {
public:
	void buildA() override {
		cout << "BuildA With BMW " << endl;
	}
	void buildB() override {
		cout << "BuildB With BMW " << endl;
	}
	void buildC() override {
		cout << "BuildC With BMW " << endl;
	}
	void buildD() override {
		cout << "BuildD With BMW " << endl;
	}

};

class FactoryBENZ : public factory {
public:
	void buildA() override {
		cout << "BuildA With BENZ " << endl;
	}
	void buildB() override {
		cout << "BuildB With BENZ " << endl;
	}
	void buildC() override {
		cout << "BuildC With BENZ " << endl;
	}
	void buildD() override {
		cout << "BuildD With BENZ " << endl;
	}

};

class FactoryTOYOTA : public factory {
public:
	void buildCar() {
		this->buildA();
		this->buildB();
		this->buildD();
		this->buildC();
		this->buildE();
		cout << "Build Finised!" << endl;
	}

	void buildA() override {
		cout << "BuildA With TOYOTA " << endl;
	}
	void buildB() override {
		cout << "BuildB With TOYOTA " << endl;
	}
	void buildC() override {
		cout << "BuildC With TOYOTA " << endl;
	}
	void buildD() override {
		cout << "BuildD With TOYOTA " << endl;
	}

	void buildE() {
		cout << "BuildE With TOYOTA " << endl;
	}

};

int main() {

	factory *p1 = new FactoryBMW();
	factory *p2 = new FactoryBENZ();
	factory *p3 = new FactoryTOYOTA();

	p1->buildCar();
	p2->buildCar();
	p3->buildCar();


	delete p1, p2, p3;

    return 0;
}

Strategy mode

The problems to be solved by strategy pattern and Template pattern are the same (similar) in order to decouple the concrete implementation of business logic (algorithm) from the abstract interface. Strategy pattern encapsulates logic (algorithm) into a class (Context), the implementation of the specific algorithm is implemented in the composite object through combination, and then the implementation of the abstract interface is delegated to the composite object through delegation.

#include<iostream>
using namespace std;

class Stratefy {
public:
	virtual ~Stratefy() {}
	virtual void sort(int arr[], int N) = 0;
};

class Context {
private:
	Stratefy* _strategy;
	int *_arr;
	int _size;

public:
	Context() : _arr(nullptr), _size(0), _strategy(nullptr) {}
	Context(int arr[], int n) : _arr(arr), _size(n){}

	void setData(int arr[], int n) {
		this->_arr = arr;
		this->_size = n;
	}	
	void setSortStrategy(Stratefy *p) {
		this->_strategy = p;
	}
	void sort() {
		this->_strategy->sort(_arr, _size);
	}
	void print() {
		for (int i = 0; i < _size; i++) {
			cout << _arr[i] << " ";
		}
		cout << endl;
	}
};

class BubbleSort : public Stratefy{
public:
	BubbleSort(){}
	~BubbleSort(){}
	void sort(int arr[], int N) override {
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N - i - 1; j++) {
				if (arr[j] > arr[j + 1]) {
					int temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
				}
			}
		}
	}

};

class SelectionSort : public Stratefy{
public:
	SelectionSort(){}
	~SelectionSort(){}
	void sort(int arr[], int N) override {
		int k;
		for (int i = 0; i < N; i++) {
			k = i;
			for (int j = i + 1; j < N; j++) {
				if (arr[k] > arr[j]) {
					k = j;
				}
			}
			int temp = arr[i];
			arr[i] = arr[k];
			arr[k] = temp;
		}
	}

};

class InsertSort : public Stratefy{
public:
	InsertSort(){}
	~InsertSort(){}
	void sort(int arr[], int N) override {
		int i, j;
		for (i = 1; i < N; i++) {
			for (j = i - 1; j >= 0; j--) {
				if (arr[i] > arr[j]) {
					break;
				}
				int temp = arr[i];
				for (int k = i - 1; k > j; k--) {
					arr[k + 1] = arr[k];
				}
				arr[j + 1] = temp;
			}
		}
	}

};





int main() {
	Context* ctx = new Context();
	int arr[] = {23, 58, -4, 59, -48, 5987, 85, 85, -4864, 352};
	ctx->setData(arr, sizeof(arr) / sizeof(int));
	cout << "before sort :";
	ctx->print();

	Stratefy *p1 = new BubbleSort();
	ctx->setSortStrategy(p1);
	ctx->sort();
	cout << "after bubble sort:";
	ctx->print();

	Stratefy *p2 = new SelectionSort();
	ctx->setSortStrategy(p2);
	ctx->sort();
	cout << "after SelectionSort sort:";
	ctx->print();
	
	Stratefy *p3 = new InsertSort();
	ctx->setSortStrategy(p3);
	ctx->sort();
	cout << "after InsertSort sort:";
	ctx->print();
	
	delete ctx, p1, p2, p3;
    return 0;
}
Observer mode

The problem to be solved by the Observer mode is to establish a Subject to many dependency, and when the "one" changes, the many that depend on the "one" can also change synchronously

For example, relative to a hotel, the specific observer is equivalent to the hotel front desk, The front desk is waiting for observation (there are several at the front desk). If a guest comes, let it register his personal information. The object is equivalent to a waiter, and the specific object is equivalent to a specific room. After registering at the front desk, you can ask the waiter to take him to a specific room to check in, and the waiter records the check-in information. The following notes focus on the above actions.

#include<iostream>
#include <map>
using namespace std;

class AbstracrSubject;

/*&&&&&&&&&&&&&&&&&&&&&&& Observer &&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
class AbstractObserser {//Hotel, the hotel can save information and receive information
public:
	AbstractObserser(string s):name(s){}//Save information
	virtual ~AbstractObserser(){}

	virtual void update(AbstracrSubject *p) = 0;//Receive information

	inline string getName() {
		return name;
	}
    
protected:
	string name;
};
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/

/*--------------------- Subject ---------------------------*/
class AbstracrSubject {//Attendant, take to the room and save the check-in information
protected:
	std::map<string, AbstractObserser*> _observsers;

public:
	virtual int getDate() = 0;
    
	virtual void addObserver(AbstractObserser *p) {//Take it to the room
		_observsers[p->getName()] = p;
	}
	virtual void notify(string s) {//The waiter records the check-in
		if (_observsers.find(s) == _observsers.end()) {
			cout << "not found any observer!" << endl;
		} else {
			_observsers[s]->update(this);
		}
	}

};
/*-------------------------------------------------------*/

/ ConcreteObserverA\B //
class Observer : public AbstractObserser {//The front desk can register information
public:
	Observer(string s) : AbstractObserser(s) {}
	~Observer(){}

	void update(AbstracrSubject *p) override {
		cout << "Update Observer! total = " << p->getDate() << " observer = " << this << endl;
	}
};

class Observer2 : public AbstractObserser {
public:
	Observer2(string s) : AbstractObserser(s) {}
	~Observer2(){}

	void update(AbstracrSubject *p) override {
		cout << "Update Observer2! total = " << p->getDate() << " observer = " << this << endl;
	}

	
};
///

/****************************** ConcreteSubject ******************************/
class Subject : public AbstracrSubject {//Room, can query customer room information
public:
	Subject(){}
	~Subject(){}

	void add() {
		this->total++;
		this->notify(to_string(this->total));
	}
	int getDate() override{
		return total;
	}
private:
	int total;
};
/****************************************************************************/
int main() {
	Subject *subject = new Subject();//A waiter
	AbstractObserser *p1 = new Observer("1");//Check in when a guest comes
	AbstractObserser *p2 = new Observer2("2");
	AbstractObserser *p3 = new Observer("3");
	AbstractObserser *p4 = new Observer2("4");
	AbstractObserser *p5 = new Observer("5");
	AbstractObserser *p6 = new Observer2("6");
	AbstractObserser *p7 = new Observer("7");

	subject->addObserver(p1);//Bring the guest to the room
	subject->addObserver(p2);
	subject->addObserver(p3);
	subject->addObserver(p4);
	subject->addObserver(p5);
	subject->addObserver(p6);
	subject->addObserver(p7);

	subject->add();
	cout << "------------------" << endl;
	
	subject->add();
	cout << "------------------" << endl;
	
	subject->add();
	cout << "------------------" << endl;
	
	subject->add();
	cout << "------------------" << endl;
	
	subject->add();
	cout << "------------------" << endl;
	
	subject->add();
	cout << "------------------" << endl;
	
    return 0;
}

Command mode

Command mode realizes the decoupling between the object calling the operation and the specific implementer of the operation by encapsulating the request into an object (command) and storing the Receiver of the request into a concrete ConcreteCommand class (Receiver).

#include<iostream>
using namespace std;

class Receiver {
public:
	Receiver(){}
	virtual ~Receiver(){}

	virtual void doCommand(int n) {
		if (n <= 1)
			cout << "Execute Command! <= 1!" << endl;
		else 
			cout << "Execute Command > 1!" << endl;
	}
};

class Receiver2 : public Receiver{
public:
	Receiver2(){}
	virtual ~Receiver2(){}

	void doCommand(int n) override{
		if (n < 10)
			cout << "Execute Command < 10!" << endl;
		else
			cout << "Execute Command >= 10 !" << endl;
	}
};

class Command {
protected:
	Receiver *_receiver;

public:
	Command(Receiver *p) : _receiver(p){}
	virtual ~Command(){}

	virtual void operator()(int n) = 0;
};

class ConcreateCommand : public Command {
public:
	ConcreateCommand(Receiver *p) : Command(p){}


	void operator()(int n) override {
		_receiver->doCommand(n);
	}
};

class ConcreateCommand2 : public Command {
public:
	ConcreateCommand2(Receiver *p) : Command(p){}

	void operator()(int n) override {
		_receiver->doCommand(n);
	}
};

class Invoker {
private:
	Command* _command;
public:
	Invoker() : _command(nullptr) {

	}
	Invoker(Command *p) : _command(p) {

	}
	virtual ~Invoker(){}

	void setCommand(Command *p) {
		_command = p;
	}

	void executeCommand(int n) {
		if (_command) {
			(*_command)(n);
		}
	}
};

int main() {
	Invoker *invoker = new Invoker();
	Receiver *receiver = new Receiver();
	Receiver *receiver2 = new Receiver2();
	Command *command = new ConcreateCommand(receiver);
	Command *command2 = new ConcreateCommand2(receiver2);
    
	invoker->setCommand(command);
	invoker->executeCommand(1);
	invoker->executeCommand(2);
	
	invoker->setCommand(command2);
	invoker->executeCommand(1);
	invoker->executeCommand(20);

	delete invoker, receiver, command;
	return 0;
} 
Visitor mode

Define new operations that act on these elements without changing the class

#include <iostream>
#include <string>
#include <map>
/// Element 
using namespace std;
class Visotor;
class Node {
public: 
	virtual ~Node(){}
	virtual void accept(Visotor *visitor) = 0;
};

/// Visitor 
class Visotor {
public:
	virtual ~Visotor(){}
	virtual void visit(Node * node) = 0 ;
};

/// ConcentrateElementA 
class NodeA : public Node {
	friend class VisitorA;
private:
	string s;
	int n;
public:
	NodeA() {
		s = "Hello KKB";
		n = 666;
	}
	virtual ~ NodeA(){}

	void accept(Visotor* vistor) override {
		vistor->visit(this);
	}
};
/// ConcentrateElementB 
class NodeB : public Node {
	friend class VisitorB;
private:
	std::map<string, int> _map;
	int n;
public:
	NodeB() {
		_map["aa"] = 34;
		_map["bb"] = 54;
		_map["cc"] = 32;
	}
	virtual ~ NodeB(){}

	void accept(Visotor* vistor) override {
		vistor->visit(this);
	}
};
/// ConcreteVisitorA 
class VisitorA : public Visotor {
public:
	void visit(Node *node) override{
		NodeA *p = (NodeA *)node;
		cout << "NodeA.s = " << p->s << " NodeA.n = " << p->n << endl;
	}
};

/// ConcreteVisitorB 
class VisitorB : public Visotor {
public:
	void visit(Node *node) override{
		NodeB *p = (NodeB *)node;
		cout << "-------------- NodeB ---- map begin ------" << endl;
		for (auto e : p->_map) {
			cout << "key = " << e.first << " value = " << e.second << endl;
		}
		
		cout << "-------------- NodeB ---- map end ------" << endl;
		
	}
};

int main() {

	Node *p1 = new NodeA();
	Node *p2 = new NodeB();

	Visotor *p3 = new VisitorA();
	Visotor *p4 = new VisitorB();

	p1->accept(p3);
	p2->accept(p4);

	delete p1, p2, p3, p4;
    return 0;
}

Responsibility chain model

Make multiple objects have the opportunity to process the request, so as to avoid the coupling relationship between the sender and receiver of the request. Connect the object into a chain and pass the request along the chain until an object processes it.

#include<iostream>
using namespace std;

class Handler {
private:
protected:
	Handler *_nextHandler;
public:
	virtual void setNextHandler(Handler *p) {
		_nextHandler = p;
	}
	virtual void dealRequest(int day) = 0;
	virtual void request(int day) {
		cout << "request for " << day << "days!" << endl;
		if (this->_nextHandler)
			this->_nextHandler->dealRequest(day);
		else 
			cout << "not need request, because next handler is null!" << endl;
	}
};

class Eployee : public Handler {
	void dealRequest(int day) override {
		cout << "You don't have permission and need to be processed and approved by your superior!" << endl;
		if (this->_nextHandler) {
			this->_nextHandler->dealRequest(day);
		}
	} 
};

class TeamLeader : public Handler {
public:
	void dealRequest(int day) override {
		
		if (day <= 3) {
			cout << "Less than three days, directly approved! " << endl;
		} else {
			cout << "For more than three days, it needs to be approved by the superior" << endl;
			if (this->_nextHandler) {
				this->_nextHandler->dealRequest(day);
			}
		}
	} 
};

class Mannager : public Handler {
public:
	void dealRequest(int day) override {
		
		if (day <= 7) {
			cout << "Less than 7 days, directly approved! " << endl;
		} else {
			cout << "It is more than 7 days and needs to be approved by the superior" << endl;
			if (this->_nextHandler) {
				this->_nextHandler->dealRequest(day);
			}
		}
	} 
};

class CEO : public Handler {
public:
	void dealRequest(int day) override {
		
		if (day <= 15) {
			cout << "Less than 15 days, directly approved! " << endl;
		} else {
			cout << "More than 15 days, reject the application!" << endl;
		}
	} 
};

int main() {
	Handler *p1 = new Eployee();
	Handler *p2 = new TeamLeader();
	Handler *p3 = new Mannager();
	Handler *p4 = new CEO();

	p1->setNextHandler(p2);
	p2->setNextHandler(p3);
	p3->setNextHandler(p4);
	p4->setNextHandler(nullptr);

	p1->request(3);
	p1->request(5);
	p1->request(10);
	p1->request(30);

	delete p1, p2, p3, p4;
    return 0;
}

Iterator mode

Provides a way to access the elements of an aggregate object sequentially, rather than exposing the internal representation of the object

#include<iostream>
#include <vector>
using namespace std;
namespace master {

template<class T>
class Aggregate {
public:
	Aggregate(){}
	virtual ~Aggregate(){}

	virtual void push(T t) = 0;
	virtual T& operator[](int idx) = 0;
	virtual int size() = 0;
};

template<class T>
class Iterator {
public:
	Iterator(){}
	virtual ~Iterator(){}

	virtual void begin() = 0;
	virtual void next() = 0;
	virtual T* currentItem() = 0;
	virtual bool end() = 0;
};

template<class T>
class ConcreateAggregate : public Aggregate<T> {
public:
	void push(T t) override {
		_data.push_back(t);
	}
	T& operator[](int idx) override {
		return _data[idx];
	}
	int size() override {
		return _data.size();
	}

private:
	std::vector<T> _data;
};

template<class T>
class ConcreteIterator : public Iterator<T> {
private:
	Aggregate<T> *_agrg;
	int _cursour;
public:
	ConcreteIterator(Aggregate<T> *p) : _agrg(p), _cursour(0) {

	}
	virtual ~ConcreteIterator(){}

	void begin() override {
		_cursour = 0;
	}
	virtual void next() {
		if (_cursour >= _agrg->size()) return ;
		_cursour++;
	}
	virtual T* currentItem(){
		if (_agrg) {
			return &((*_agrg)[_cursour]);
		} else {
			return nullptr;
		}
	}
	bool end() override {
		return _cursour >= _agrg->size();
	}
};
}
int main() {
	master::Aggregate<int> *aggr = new master::ConcreateAggregate<int>();
	aggr->push(1);
	aggr->push(2);
	aggr->push(3);
	aggr->push(4);
	aggr->push(5);
    
	master::Iterator<int> *it = new master::ConcreteIterator<int>(aggr);
	for (it->begin(); !it->end(); it->next()) {
		cout << *it->currentItem() << endl;
	}

	delete aggr, it;
    return 0;
}

Summary:
Design patterns are still oriented to a project. The best way to understand is to draw UML diagrams to implement a program

`

Topics: C++ Design Pattern