前面两篇文章分别整理了设计模式三大类中的创建型模式和结构型模式:
今天我们再来整理一下最后一部分,行为型模式。
首先,什么是行为型模式?
行为型模式(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