C + + design pattern sorting 012 - responsibility chain pattern, observer pattern and state pattern

Posted by BobcatM on Tue, 08 Mar 2022 05:22:09 +0100

catalogue

18. Responsibility chain model

18.1 example 2

19. Observer mode

19.1 example 2

20. Status mode

18. Responsibility chain model

Responsibility chain mode: 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 these objects into a chain and pass the request along the chain until an object processes it.

The handler in the responsibility chain is responsible for processing the request. The customer only needs to send the request to the responsibility chain without paying attention to the processing details of the request and the transmission of the request. All responsibility chains decouple the sender of the request from the handler of the request.

/*
* Key code: indicate its superior in Handler, judge whether it is appropriate in handleRequest(), and pass it to the superior if it is not appropriate.
*/
#include <iostream>

using namespace std;

enum RequestLevel
{
    Level_One = 0,
    Level_Two,
    Level_Three,
    Level_Num
};

//The abstract Handler role provides a unified interface to the responsibility chain.
class Leader
{
public:
    Leader(Leader* leader):m_leader(leader){}
    virtual ~Leader(){}
    virtual void handleRequest(RequestLevel level) = 0;
protected:
    Leader* m_leader;
};

//Concrete Handler role
class Monitor:public Leader   //Chain buckle 1
{
public:
    Monitor(Leader* leader):Leader(leader){}
    void handleRequest(RequestLevel level)
    {
        if(level < Level_Two)
        {
            cout << "Mointor handle request : " << level << endl;
        }
        else
        {
            m_leader->handleRequest(level);
        }
    }
};

//Concrete Handler role
class Captain:public Leader    //Chain buckle 2
{
public:
    Captain(Leader* leader):Leader(leader){}
    void handleRequest(RequestLevel level)
    {
        if(level < Level_Three)
        {
            cout << "Captain handle request : " << level << endl;
        }
        else
        {
            m_leader->handleRequest(level);
        }
    }
};

//Concrete Handler role
class General:public Leader   //Chain buckle 3
{
public:
    General(Leader* leader):Leader(leader){}
    void handleRequest(RequestLevel level)
    {
        cout << "General handle request : " << level << endl;
    }
};

int main()
{
    Leader* general = new General(nullptr);
    Leader* captain = new Captain(general);
    Leader* monitor = new Monitor(captain);
    monitor->handleRequest(Level_One);

    delete monitor;
    monitor = nullptr;
    delete captain;
    captain = nullptr;
    delete general;
    general = nullptr;
    return 0;
}

18.1 example 2

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 these objects into a chain and pass the request along the chain until an object processes it.

The idea is very simple, considering that employees ask for a raise.

There are three levels of managers in the company: general manager, director and manager. If an employee asks for a raise, he should apply to the manager in charge. If the amount of raise is within the authority of the manager, the manager can approve it directly, otherwise the application will be submitted to the director. The handling method of the director is the same, and the general manager can handle all requests. This is the typical responsibility chain mode. The processing of requests forms a chain until an object processes the request. UML diagram of this example is given.

 

The implementation of the code is relatively simple, as shown below:

//Abstract Manager
class Manager
{
protected:
	Manager *m_manager;
	string m_name;
public:
	Manager(Manager *manager, string name):m_manager(manager), m_name(name){}
	virtual void DealWithRequest(string name, int num)  {}
};

//manager
class CommonManager: public Manager
{
public:
	CommonManager(Manager *manager, string name):Manager(manager,name) {}
	void DealWithRequest(string name, int num) 
	{
		if(num < 500) //Within the authority of the manager
		{
			cout<<"manager"<<m_name<<"approval"<<name<<"Raise salary"<<num<<"element"<<endl<<endl;
		}
		else
		{
			cout<<"manager"<<m_name<<"If it cannot be handled, it shall be handled by the director"<<endl;
			m_manager->DealWithRequest(name, num);
		}
	}
};

//chief inspector
class Majordomo: public Manager
{
public:
	Majordomo(Manager *manager, string name):Manager(manager,name) {}
	void DealWithRequest(string name, int num) 
	{
		if(num < 1000) //Within the authority of the director
		{
			cout<<"chief inspector"<<m_name<<"approval"<<name<<"Raise salary"<<num<<"element"<<endl<<endl;
		}
		else
		{
			cout<<"chief inspector"<<m_name<<"If it cannot be handled, it shall be handled by the general manager"<<endl;
			m_manager->DealWithRequest(name, num);
		}
	}
};

//general manager
class GeneralManager: public Manager
{
public:
	GeneralManager(Manager *manager, string name):Manager(manager,name) {}
	void DealWithRequest(string name, int num)  //The general manager can handle all requests
	{
		cout<<"general manager"<<m_name<<"approval"<<name<<"Raise salary"<<num<<"element"<<endl<<endl;
	}
};

// The customer call method is:

//Test case
int main()
{	
	Manager *general = new GeneralManager(NULL, "A"); //Set up a superior. The general manager has no superior
	Manager *majordomo = new Majordomo(general, "B"); //Set up superior
	Manager *common = new CommonManager(majordomo, "C"); //Set up superior
	common->DealWithRequest("D",300);   //Employee D asked for a raise
	common->DealWithRequest("E", 600);
	common->DealWithRequest("F", 1000);
	delete common; 
	delete majordomo; 
	delete general;
	return 0;
}

reference material: https://blog.csdn.net/wuzhekai1985/article/details/6673892

reference material: https://www.cnblogs.com/chengjundu/p/8473564.html

 

19. Observer mode

Observer mode: defines a one to many dependency between objects. When the state of an object changes, all objects that depend on it should be notified and updated automatically.

Basically, the observer and the observer must contain two roles.

                1. The observed object itself should contain a container to store the observer object. When the observed object itself changes, all the observer objects in the container should be notified to update automatically.
                2. The observer object can be registered in the of the observer. After registration, it can detect the changes of the observer and receive the notification of the observer. Of course, the observer can also be cancelled and the monitoring of the observed can be stopped.

/*
* Key code: add an ArrayList in the target class to store the observers.
*/
#include <iostream>
#include <list>
#include <memory>

using namespace std;

class View;

//Observer abstract class data model
class DataModel
{
public:
    virtual ~DataModel(){}
    virtual void addView(View* view) = 0;
    virtual void removeView(View* view) = 0;
    virtual void notify() = 0;   //Notification function
};

//Observer abstract class view
class View
{
public:
    virtual ~View(){ cout << "~View()" << endl; }
    virtual void update() = 0;
    virtual void setViewName(const string& name) = 0;
    virtual const string& name() = 0;
};

//Specific observed class, integer model
class IntDataModel:public DataModel
{
public:
    ~IntDataModel()
    {
        m_pViewList.clear();
    }

    virtual void addView(View* view) override
    {
        shared_ptr<View> temp(view);
        auto iter = find(m_pViewList.begin(), m_pViewList.end(), temp);
        if(iter == m_pViewList.end())
        {
            m_pViewList.push_front(temp);
        }
        else
        {
            cout << "View already exists" << endl;
        }
    }

    void removeView(View* view) override
    {
        auto iter = m_pViewList.begin();
        for(; iter != m_pViewList.end(); iter++)
        {
            if((*iter).get() == view)
            {
                m_pViewList.erase(iter);
                cout << "remove view" << endl;
                return;
            }
        }
    }

    virtual void notify() override
    {
        auto iter = m_pViewList.begin();
        for(; iter != m_pViewList.end(); iter++)
        {
            (*iter).get()->update();
        }
    }

private:
    list<shared_ptr<View>> m_pViewList; 
};

//Specific Observer class table view
class TableView : public View
{
public:
    TableView() : m_name("unknow"){}
    TableView(const string& name) : m_name(name){}
    ~TableView(){ cout << "~TableView(): " << m_name.data() << endl; }

    void setViewName(const string& name)
    {
        m_name = name;
    }

    const string& name()
    {
        return m_name;
    }

    void update() override
    {
        cout << m_name.data() << " update" << endl;
    }

private:
    string m_name;
};

int main()
{
    /*
    * It should be added here that in this example code, once the View is registered to the DataModel class, the DataModel will be automatically resolved when it is parsed     
    * The View object stored in the internal container, so the registered View object does not need to be delete d manually, and then deleting the View object will make an error.
    */
    
    View* v1 = new TableView("TableView1");
    View* v2 = new TableView("TableView2");
    View* v3 = new TableView("TableView3");
    View* v4 = new TableView("TableView4");

    IntDataModel* model = new IntDataModel;
    model->addView(v1);
    model->addView(v2);
    model->addView(v3);
    model->addView(v4);

    model->notify();

    cout << "-------------\n" << endl;

    model->removeView(v1);

    model->notify();

    delete model;
    model = nullptr;

    return 0;
}

19.1 example 2

Defines a one to many dependency between objects. When the state of an object changes, all objects that depend on it are notified and automatically updated. It also has two aliases, dependencies and publish subscribe.

Take Blog subscription as an example. When a blogger publishes a new article, that is, the blogger's status changes, those subscribed readers will receive a notice and take corresponding actions, such as reading an article or collecting it. There is a one to many dependency between bloggers and readers. The corresponding UML diagram design is given below.

 

You can see that there is a linked list of observers (subscribers) in the blog class. When the status of the blog changes, Notify all observers through the Notify member function to tell them that the status of the blog has been updated. The observer obtains the status information of the blog through the Update member function. The code implementation is not difficult. An implementation of C + + is given below.

//Observer
class Observer  
{
public:
	Observer() {}
	virtual ~Observer() {}
	virtual void Update() {} 
};

//Blog
class Blog  
{
public:
	Blog() {}
	virtual ~Blog() {}
	void Attach(Observer *observer) { m_observers.push_back(observer); }	 //Add observer
	void Remove(Observer *observer) { m_observers.remove(observer); }        //Remove observer
	void Notify() //Notify the observer
	{
		list<Observer*>::iterator iter = m_observers.begin();
		for(; iter != m_observers.end(); iter++)
			(*iter)->Update();
	}
	virtual void SetStatus(string s) { m_status = s; } //Set status
	virtual string GetStatus() { return m_status; }    //Get status
private:
	list<Observer* > m_observers; //Observer list
protected:
	string m_status; //state
};


// The above is the base class of observer and blog, which defines the general interface. Blog class mainly completes the operations of adding, removing and notifying observers. Setting and obtaining status is only a default implementation. Their corresponding subclass implementations are given below.

//Specific blog category
class BlogCSDN : public Blog
{
private:
	string m_name; //Blogger name
public:
	BlogCSDN(string name): m_name(name) {}
	~BlogCSDN() {}
	void SetStatus(string s) { m_status = "CSDN notice : " + m_name + s; } //Specific setting status information
	string GetStatus() { return m_status; }
};

//Specific observer
class ObserverBlog : public Observer   
{
private:
	string m_name;  //Observer name
	Blog *m_blog;   //Observation of the blog, of course, in the form of a linked list is better, you can observe multiple blogs
public: 
	ObserverBlog(string name,Blog *blog): m_name(name), m_blog(blog) {}
	~ObserverBlog() {}
	void Update()  //Get update status
	{ 
		string status = m_blog->GetStatus();
		cout<<m_name<<"-------"<<status<<endl;
	}
};

// Customer usage:

//Test case
int main()
{
	Blog *blog = new BlogCSDN("wodehao0808");
	Observer *observer1 = new ObserverBlog("niuniu", blog);
	blog->Attach(observer1);
	blog->SetStatus("Publish rendering test");
	blog->Notify();
	
    delete blog; 
    delete observer1;
	
    return 0;
}

 

reference material: https://blog.csdn.net/wuzhekai1985/article/details/6674984

reference material: https://www.cnblogs.com/chengjundu/p/8473564.html

 

20. Status mode

State mode: allows an object to change its behavior when its internal state changes. Object appears to have modified its class. It can be used in two ways:

(1) the behavior of an object depends on its state, and it must change its behavior according to the state at runtime.

(2) an operation contains a large number of conditional statements with multiple branches, and these branches depend on the state of the object.

The example of this paper is the first case. Taking the war as an example, it is assumed that a war needs to go through four stages: early stage, middle stage, late stage and end. When the war is in different stages, the behavior of the war is different, that is to say, the behavior of the war depends on the stage and changes dynamically with the advance of time. The corresponding UML diagram is given below.

 

The implementation code is relatively simple. War class and State class are given. War class contains State object (pointer form).

class War;
class State 
{
public:
	virtual void Prophase() {}
	virtual void Metaphase() {}
	virtual void Anaphase() {}
	virtual void End() {}
	virtual void CurrentState(War *war) {}
};

//Warfare
class War
{
private:
	State *m_state;  //Current status
	int m_days;      //Duration of war
public:
	War(State *state): m_state(state), m_days(0) {}
	~War() { delete m_state; }
	int GetDays() { return m_days; }
	void SetDays(int days) { m_days = days; }
	void SetState(State *state) { delete m_state; m_state = state; }
	void GetState() { m_state->CurrentState(this); }
};

Specific status classes are given:

//The war is over
class EndState: public State
{
public:
	void End(War *war) //Specific actions at the end stage
	{
		cout<<"The war is over"<<endl;
	}
	void CurrentState(War *war) { End(war); }
};

//later stage
class AnaphaseState: public State
{
public:
	void Anaphase(War *war) //Later specific behavior
	{
		if(war->GetDays() < 30)
			cout<<"The first"<<war->GetDays()<<"Day: at the end of the war, both sides fought to the death"<<endl;
		else
		{
			war->SetState(new EndState());
			war->GetState();
		}
	}
	void CurrentState(War *war) { Anaphase(war); }
};

//metaphase
class MetaphaseState: public State
{
public:
	void Metaphase(War *war) //Specific behavior in the medium term
	{
		if(war->GetDays() < 20)
			cout<<"The first"<<war->GetDays()<<"Day: in the middle of the war, it entered the stalemate stage, and both engines lost"<<endl;
		else
		{
			war->SetState(new AnaphaseState());
			war->GetState();
		}
	}
	void CurrentState(War *war) { Metaphase(war); }
};

//early stage
class ProphaseState: public State
{
public:
	void Prophase(War *war)  //Specific behavior in the early stage
	{
		if(war->GetDays() < 10)
			cout<<"The first"<<war->GetDays()<<"Tian: at the beginning of the war, both sides came and went to test each other"<<endl;
		else
		{
			war->SetState(new MetaphaseState());
			war->GetState();
		}
	}
	void CurrentState(War *war) { Prophase(war); }
};

// Usage:

//Test case
int main()
{
	War *war = new War(new ProphaseState());
	for(int i = 1; i < 40;i += 5)
	{
		war->SetDays(i);
		war->GetState();
	}
	delete war;
	return 0;
}

 

reference material: https://blog.csdn.net/wuzhekai1985/article/details/6675799

Topics: C++ Design Pattern