前面兩篇文章分別整理了設計模式三大類中的創建型模式和結構型模式:
今天我們再來整理一下最後一部分,行爲型模式。
首先,什麼是行爲型模式?
行爲型模式(Behavioral Pattern)是指對在不同對象之間劃分責任和算法進行抽象化的設計模式,它不僅關注類和對象的結構,而且重點關注他們之間的相互作用。
對於一個系統來說,對象不是孤立運行的,對象之間可以通過相互通信和協作完成某些複雜的功能,對象之間是相互影響的。
行爲型模式分爲類行爲型模式和對象行爲型模式。類行爲型模式使用繼承關係在幾個類之間分配行爲,主要通過多態等方式來分配父類與子類的職責。對象行爲型模式則是通過對象的聚合關聯關係來分配職責。大部分行爲型設計模式都屬於對象行爲型設計模式。
行爲型模式包含11種具體的設計模式,分別是:職責鏈模式(Chain of Responsibility Pattern)、命令模式(Command Pattern)、解釋器模式(Interpreter Pattern)、迭代器模式(Iterator Pattern)、中介者模式(Mediator Pattern)、備忘錄模式(Memento Pattern)、觀察者模式(Observer Pattern)、狀態模式(State Pattern)、策略模式(Strategy Pattern)、模板方法模式(Template Method Pattern)、訪問者模式(Visitor Pattern)。
我們選其中的5種來介紹。
1. 命令模式(Command Pattern)
命令模式又稱動作模式(Action Pattern)或事務模式(Transaction Pattern)。在這種模式下,將一個請求封裝成一個對象,從而可用不同的請求對客戶進行參數化,對請求進行排隊或記錄日誌,並支持可撤銷操作。
命令模式可以對發送者和接收者完全解耦,發送者與接收者之間沒有直接引用關係,發送請求的對象只需知道如何發送請求,而不需要知道如何完成請求。
命令模式包含5個角色:
(1) 抽象命令類Command
(2) 具體命令類ConcreteCommand
(3) 調用者Invoker
(4) 接收者Receiver
(5) 客戶類Client
示例代碼:
#include <iostream>
#include "ConcreteCommand.h"
#include "Invoker.h"
#include "Receiver.h"
using namespace std;
int main(int argc, char *argv[])
{
Receiver * pReceiver = new Receiver(); // 定義一個接收者
ConcreteCommand * pCommand = new ConcreteCommand(pReceiver); // 定義一個具體命令
Invoker * pInvoker = new Invoker(pCommand); //定義命令的調用者
pInvoker->call();
delete pReceiver;
delete pCommand;
delete pInvoker;
return 0;
}
///////////////////////////////////////////////////////////
// Receiver.h
// Definition of the Class Receiver
///////////////////////////////////////////////////////////
#ifndef __RECEIVER_H__
#define __RECEIVER_H__
class Receiver
{
public:
Receiver();
virtual ~Receiver();
void action();
};
#endif
///////////////////////////////////////////////////////////
// Receiver.cpp
// Implementation of the Class Receiver
///////////////////////////////////////////////////////////
#include "Receiver.h"
#include <iostream>
using namespace std;
Receiver::Receiver()
{
}
Receiver::~Receiver()
{
}
void Receiver::action()
{
cout << "Receiver action." << endl;
}
///////////////////////////////////////////////////////////
// ConcreteCommand.h
// Definition of the Class ConcreteCommand
///////////////////////////////////////////////////////////
#ifndef __CONCRETE_COMMAND_H__
#define __CONCRETE_COMMAND_H__
#include "Command.h"
#include "Receiver.h"
class ConcreteCommand : public Command
{
public:
ConcreteCommand(Receiver * pReceiver);
virtual ~ConcreteCommand();
virtual void execute();
private:
Receiver *m_pReceiver;
};
#endif
///////////////////////////////////////////////////////////
// ConcreteCommand.cpp
// Implementation of the Class ConcreteCommand
///////////////////////////////////////////////////////////
#include "ConcreteCommand.h"
#include <iostream>
using namespace std;
ConcreteCommand::ConcreteCommand(Receiver *pReceiver)
{
m_pReceiver = pReceiver;
}
ConcreteCommand::~ConcreteCommand()
{
}
void ConcreteCommand::execute()
{
cout << "ConcreteCommand::execute" << endl;
m_pReceiver->action();
}
///////////////////////////////////////////////////////////
// Invoker.h
// Definition of the Class Invoker
///////////////////////////////////////////////////////////
#ifndef __INVOKER_H__
#define __INVOKER_H__
#include "Command.h"
class Invoker
{
public:
Invoker(Command * pCommand);
virtual ~Invoker();
void call();
private:
Command *m_pCommand;
};
#endif
///////////////////////////////////////////////////////////
// Invoker.cpp
// Implementation of the Class Invoker
///////////////////////////////////////////////////////////
#include "Invoker.h"
#include <iostream>
using namespace std;
Invoker::Invoker(Command * pCommand)
{
m_pCommand = pCommand;
}
Invoker::~Invoker()
{
}
void Invoker::call()
{
cout << "Invoker calling" << endl;
m_pCommand->execute();
}
命令模式中,抽象命令類中聲明瞭用於執行請求的execute()等方法,通過這些方法可以調用請求接收者的相關操作;具體命令類是抽象命令類的子類,實現了在抽象命令類中聲明的方法,它對應具體的接收者對象,將接收者對象的動作綁定其中;調用者即請求的發送者,又稱爲請求者,它通過命令對象來執行請求;執行者(接收者)執行與請求相關的操作,它具體實現對請求的業務處理。
命令模式的本質是對命令進行封裝,將發出命令的責任和執行命令的責任分隔開。命令模式將請求本身作爲一個對象,這個對象和其他對象一樣可以被存儲和傳遞。該模式可以降低系統的耦合度,方便增加新的命令,可以比較容易地實現命令隊列和宏命令,並實現對請求的撤銷和恢復。
這個模式第一遍理解起來會比較抽象有難度,多看兩遍並加以思考就能很好地理解它了。想象一臺電視機和遙控器,電視機是命令的接收者Receiver(和執行者),遙控器是命令的發送者,而具體的命令可以是開機、關機、選擇節目等,這些命令可以抽象到一個統一的命令接口中。
2. 中介者模式(Mediator Pattern)
中介者模式是用一箇中介對象來封裝不同的對象交互,使各對象不需要顯式地相互引用,從而達到鬆散耦合的目的。
中介者模式包含四個角色:
(1) 抽象中介者Mediator
(2) 具體中介者ConcreteMediator
(3) 抽象同事類Colleague
(4) 具體同事類ConcreteColleague
示例代碼:
#include <iostream>
#include "ConcreteColleagueA.h"
#include "ConcreteMediator.h"
#include "ConcreteColleagueB.h"
using namespace std;
int main(int argc, char *argv[])
{
ConcreteColleagueA * pa = new ConcreteColleagueA();
ConcreteColleagueB * pb = new ConcreteColleagueB();
ConcreteMediator * pm = new ConcreteMediator();
pm->registered(1,pa);
pm->registered(2,pb);
// sendmsg from a to b
pa->sendmsg(2,"Hello, This is a.");
// sendmsg from b to a
pb->sendmsg(1,"Hello, This is b.");
delete pa, pb, pm;
return 0;
}
///////////////////////////////////////////////////////////
// ConcreteMediator.h
// Definition of the Class ConcreteMediator
///////////////////////////////////////////////////////////
#ifndef __CONCRETE_MEDIATOR_H__
#define __CONCRETE_MEDIATOR_H__
#include "ConcreteColleagueB.h"
#include "Mediator.h"
#include "ConcreteColleagueA.h"
#include <map>
using namespace std;
class ConcreteMediator : public Mediator
{
public:
ConcreteMediator();
virtual ~ConcreteMediator();
virtual void operation(int nWho, string str);
virtual void registered(int nWho, Colleague * aColleague);
private:
map<int,Colleague*> m_mpColleague;
};
#endif
///////////////////////////////////////////////////////////
// ConcreteMediator.cpp
// Implementation of the Class ConcreteMediator
///////////////////////////////////////////////////////////
#include "ConcreteMediator.h"
#include <map>
#include <iostream>
using namespace std;
ConcreteMediator::ConcreteMediator()
{
}
ConcreteMediator::~ConcreteMediator()
{
}
void ConcreteMediator::operation(int nWho, string str)
{
map<int,Colleague*>::const_iterator itr = m_mpColleague.find(nWho);
if(itr == m_mpColleague.end())
{
cout << "not found this colleague!" << endl;
return;
}
Colleague* pc = itr->second;
pc->receivemsg(str);
}
void ConcreteMediator::registered(int nWho, Colleague * aColleague)
{
map<int,Colleague*>::const_iterator itr = m_mpColleague.find(nWho);
if(itr == m_mpColleague.end())
{
//插入新的對象
m_mpColleague.insert(make_pair(nWho, aColleague));
//同時將中介類暴露給colleague
aColleague->setMediator(this);
}
}
///////////////////////////////////////////////////////////
// ConcreteColleagueA.h
// Definition of the Class ConcreteColleagueA
///////////////////////////////////////////////////////////
#ifndef __CONCRETE_COLLEAGUE_A_H__
#define __CONCRETE_COLLEAGUE_A_H__
#include "Colleague.h"
class ConcreteColleagueA : public Colleague
{
public:
ConcreteColleagueA();
virtual ~ConcreteColleagueA();
virtual void sendmsg(int toWho, string str);
virtual void receivemsg(string str);
};
#endif
///////////////////////////////////////////////////////////
// ConcreteColleagueA.cpp
// Implementation of the Class ConcreteColleagueA
///////////////////////////////////////////////////////////
#include "ConcreteColleagueA.h"
#include <iostream>
using namespace std;
ConcreteColleagueA::ConcreteColleagueA()
{
}
ConcreteColleagueA::~ConcreteColleagueA()
{
}
void ConcreteColleagueA::sendmsg(int toWho, string str)
{
cout << "send msg from colleagueA,to:" << toWho << endl;
m_pMediator->operation(toWho, str);
}
void ConcreteColleagueA::receivemsg(string str)
{
cout << "ConcreteColleagueA reveivemsg:" << str <<endl;
}
中介者模式中,抽象中介者用於定義一個接口,該接口用於與各同事對象之間的通信;具體中介者是抽象中介者的子類,通過協調各個同事對象來實現協作行爲,同時維護它在各個同事對象中的引用;抽象同事類定義各個同事的共有方法;具體同事類是抽象同事類的子類,每一個同事對象都引用一箇中介者對象。每一個同事對象需要和其他同事對象通信時,首先與中介者通信,通過中介者來間接完成與其他同事類的通信。在具體同事類中實現了抽象同事類中定義的方法。
通過引入中介者對象,系統原有的peer to peer的網狀結構變爲以中介者爲中心的星狀結構,中介者承擔了中轉和協調作用。中介者作爲核心,對整個系統進行控制和協調,從而簡化了對象之間的交互,並可以對對象間的交互做進一步的控制,比如不同等級同事之間的權限管理。
3. 觀察者模式(Observer Pattern)
觀察者模式用以定義對象間的一種一對多依賴關係,使得每當一個對象的狀態發生改變時,其相關的依賴對象都會得到通知並被自動更新。觀察者模式也叫發佈/訂閱模式(Publish/Subscribe Pattern)、模型/視圖模式(Model/View Pattern)、源/監聽器模式(Source/Listener Pattern)或從屬者模式(Dependents Pattern)。
觀察者模式包含4個角色,分別是:
(1) 目標Subject
(2) 具體目標ConcreteSubject
(3) 觀察者Observer
(4) 具體觀察者ConcreteObserver
示例代碼:
#include <iostream>
#include "Subject.h"
#include "Observer.h"
#include "ConcreteObserver.h"
#include "ConcreteSubject.h"
using namespace std;
int main(int argc, char *argv[])
{
Subject * subject = new ConcreteSubject();
Observer * objA = new ConcreteObserver("A");
Observer * objB = new ConcreteObserver("B");
subject->attach(objA);
subject->attach(objB);
subject->setState(1);
subject->notify();
subject->detach(objB);
subject->setState(2);
subject->notify();
delete subject;
delete objA;
delete objB;
return 0;
}
///////////////////////////////////////////////////////////
// Subject.h
// Definition of the Class Subject
///////////////////////////////////////////////////////////
#ifndef __SUBJECT_H__
#define __SUBJECT_H__
#include "Observer.h"
#include <vector>
using namespace std;
class Subject
{
public:
Subject();
virtual ~Subject();
Observer *m_Obeserver;
void attach(Observer * pObserver);
void detach(Observer * pObserver);
void notify();
virtual int getState() = 0;
virtual void setState(int i)= 0;
private:
vector<Observer*> m_vtObj;
};
#endif
///////////////////////////////////////////////////////////
// Subject.cpp
// Implementation of the Class Subject
///////////////////////////////////////////////////////////
#include "Subject.h"
Subject::Subject()
{
}
Subject::~Subject()
{
}
void Subject::attach(Observer * pObserver)
{
m_vtObj.push_back(pObserver);
}
void Subject::detach(Observer * pObserver)
{
vector<Observer*>::iterator itr;
for(itr = m_vtObj.begin(); itr != m_vtObj.end(); itr++)
{
if(*itr == pObserver)
{
m_vtObj.erase(itr);
return;
}
}
}
void Subject::notify(){
for(vector<Observer*>::iterator itr = m_vtObj.begin();
itr != m_vtObj.end();
itr++)
{
(*itr)->update(this);
}
}
///////////////////////////////////////////////////////////
// Observer.h
// Definition of the Class Observer
///////////////////////////////////////////////////////////
#ifndef __OBSERVER_H__
#define __OBSERVER_H__
class Subject;
class Observer
{
public:
Observer();
virtual ~Observer();
virtual void update(Subject * sub) = 0;
};
#endif
///////////////////////////////////////////////////////////
// ConcreteObserver.h
// Definition of the Class ConcreteObserver
///////////////////////////////////////////////////////////
#ifndef __CONCRETE_OBSERVER_H__
#define __CONCRETE_OBSERVER_H__
#include "Obeserver.h"
#include <string>
using namespace std;
class ConcreteObserver : public Obeserver
{
public:
ConcreteObserver(string name);
virtual ~ConcreteObserver();
virtual void update(Subject * sub);
private:
string m_objName;
int m_obeserverState;
};
#endif
///////////////////////////////////////////////////////////
// ConcreteObserver.cpp
// Implementation of the Class ConcreteObserver
///////////////////////////////////////////////////////////
#include "ConcreteObserver.h"
#include <iostream>
#include <vector>
#include "Subject.h"
using namespace std;
ConcreteObserver::ConcreteObserver(string name)
{
m_objName = name;
}
ConcreteObserver::~ConcreteObserver()
{
}
void ConcreteObserver::update(Subject * sub)
{
m_obeserverState = sub->getState();
cout << "update oberserver[" << m_objName << "] state:" << m_obeserverState << endl;
}
執行結果:
觀察者模式定義對象間的一種一對多依賴關係,使得每當一個對象狀態發生變化時,其相關依賴對象都會得到通知並被更新。觀察者模式可以實現表示層和數據邏輯層的分離,並在觀察目標和觀察者之間建立一個抽象的耦合,支持廣播通信。
4. 狀態模式(State Pattern)
狀態模式允許一個對象在其內部狀態改變時改變它的行爲,對象看起來似乎修改了它的類。
狀態模式包含3個角色:
(1) 環境類Context
(2) 抽象狀態類State
(3) 具體狀態類ConcreteState
示例代碼:
#include <iostream>
#include "Context.h"
#include "ConcreteStateA.h"
#include "ConcreteStateB.h"
using namespace std;
int main(int argc, char *argv[])
{
Context * c = new Context();
c->request();
c->request();
c->request();
delete c;
return 0;
}
///////////////////////////////////////////////////////////
// Context.h
// Definition of the Class Context
///////////////////////////////////////////////////////////
#ifndef __CONTEXT_H__
#define __CONTEXT_H__
#include "State.h"
class Context
{
public:
Context();
virtual ~Context();
void changeState(State * st);
void request();
private:
State *m_pState;
};
#endif
///////////////////////////////////////////////////////////
// Context.cpp
// Implementation of the Class Context
///////////////////////////////////////////////////////////
#include "Context.h"
#include "ConcreteStateA.h"
Context::Context()
{
//default is A
m_pState = ConcreteStateA::Instance();
}
Context::~Context()
{
}
void Context::changeState(State * st)
{
m_pState = st;
}
void Context::request()
{
m_pState->handle(this);
}
///////////////////////////////////////////////////////////
// ConcreteStateA.h
// Definition of the Class ConcreteStateA
///////////////////////////////////////////////////////////
#ifndef __CONCRETE_STATEA_H__
#define __CONCRETE_STATEA_H__
#include "State.h"
class ConcreteStateA : public State
{
public:
virtual ~ConcreteStateA();
static State * Instance();
void handle(Context * c);
private:
ConcreteStateA();
static State * m_pState;
};
#endif
///////////////////////////////////////////////////////////
// ConcreteStateA.cpp
// Implementation of the Class ConcreteStateA
///////////////////////////////////////////////////////////
#include "ConcreteStateA.h"
#include "ConcreteStateB.h"
#include "Context.h"
#include <iostream>
using namespace std;
State * ConcreteStateA::m_pState = NULL;
ConcreteStateA::ConcreteStateA()
{
}
ConcreteStateA::~ConcreteStateA()
{
}
State * ConcreteStateA::Instance()
{
if(NULL == m_pState)
{
m_pState = new ConcreteStateA();
}
return m_pState;
}
void ConcreteStateA::handle(Context * c)
{
cout << "Doing something in State A.\n Done, change state to B" << endl;
c->changeState(ConcreteStateB::Instance());
}
執行結果:
在狀態模式的三個角色中,環境類又稱爲上下文類,是擁有狀態的對象,在環境類中擁有一個狀態類的實例,該實例定義了當前的狀態,在具體實現時,它是一個State子類的對象,可以定義初始狀態。抽象狀態類定義了一個接口,用以封裝與環境類的特定狀態相關的行爲。具體狀態類是抽象狀態類的子類,每一個子類實現一個與環境類的一個狀態相關的行爲,每一個具體狀態類對應環境的一個具體狀態,不同具體狀態類的行爲有所不同。
5. 策略模式(Strategy Pattern)
策略模式也稱爲政策模式(Policy Pattern),定義一系列算法,將每一個算法封裝起來,並使得他們可以相互替換。策略模式可以讓算法獨立於它們的使用者而變化。
策略模式中的角色:
(1) 環境類Context
(2) 抽象策略類Strategy
(3) 具體策略類ConcreteStrategy
示例代碼:
#include <iostream>
#include "Context.h"
#include "ConcreteStrategyA.h"
#include "ConcreteStrategyB.h"
#include "Strategy.h"
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
Strategy * s1 = new ConcreteStrategyA();
Context * cxt = new Context();
cxt->setStrategy(s1);
cxt->algorithm();
Strategy *s2 = new ConcreteStrategyB();
cxt->setStrategy(s2);
cxt->algorithm();
delete s1;
delete s2;
return 0;
}
///////////////////////////////////////////////////////////
// Context.h
// definition of the Class Context
///////////////////////////////////////////////////////////
#ifndef __CONTEXT_H__
#define __CONTEXT_H__
#include "Strategy.h"
class Context
{
public:
Context();
virtual ~Context();
void algorithm();
void setStrategy(Strategy* st);
private:
Strategy *m_pStrategy;
};
#endif
///////////////////////////////////////////////////////////
// Context.cpp
// Implementation of the Class Context
///////////////////////////////////////////////////////////
#include "Context.h"
Context::Context()
{
}
Context::~Context()
{
}
void Context::algorithm()
{
m_pStrategy->algorithm();
}
void Context::setStrategy(Strategy* st)
{
m_pStrategy = st;
}
///////////////////////////////////////////////////////////
// ConcreteStrategyA.h
// Definition of the Class ConcreteStrategyA
///////////////////////////////////////////////////////////
#ifndef __CONCRETE_STRATEGY_H__
#define __CONCRETE_STRATEGY_H__
#include "Strategy.h"
class ConcreteStrategyA : public Strategy
{
public:
ConcreteStrategyA();
virtual ~ConcreteStrategyA();
void algorithm();
};
#endif
///////////////////////////////////////////////////////////
// ConcreteStrategyA.cpp
// Implementation of the Class ConcreteStrategyA
///////////////////////////////////////////////////////////
#include "ConcreteStrategyA.h"
#include <iostream>
using namespace std;
ConcreteStrategyA::ConcreteStrategyA()
{
}
ConcreteStrategyA::~ConcreteStrategyA()
{
}
void ConcreteStrategyA::algorithm()
{
cout << "use algorithm A" << endl;
}
執行結果:
在以上幾種角色中,環境類在解決某個問題時可以採用多種策略,在環境類中維護一個對抽象策略類的引用實例;抽象策略類爲所支持的算法聲明瞭抽象方法,是所有策略類的基類。具體策略類實現了在抽象策略類中定義的算法。
策略模式能夠很好的支持“開閉原則”,在不修改原有系統的基礎上可以更換算法或增加新的算法。
參考資料:https://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html