Template Pattern
开放-封闭原则: 软件实体应该是可以扩展但是不可以修改的(对扩展开放,对更改封闭)。
开闭原则希望用抽象来应对变化,开发人员应该对程序中呈现出频繁变化的部分作出抽象;
里氏替换原则: 子类对象必须能够替换掉父类对象,即在代码中将父类替换成子类,对程序本身没有影响。
里氏替换原则是为了让父类真正的被复用,子类也能子父类基础上进行扩展;
依赖倒转原则: 即针对接口编程,不要针对实现编程;程序中所有依赖关系都终止于抽象类或者接口,就是面向对象的设计。
注意将算法细节定义成保护(Protected)成员,只供模板方
法调用(子类可以)。Template 是采用继承的方式实现算法的异构,其关键点就是将通用算法封装在抽象基类中,并将不同的算法细节放到子类中实现。
Template 模式获得一种反向控制结构效果,这也是面向对象系统的分析和设计中一个原则 DIP(依赖倒置:Dependency Inversion Principles)。其含义就是父类调用子类的操作(高层模块调用低层模块的操作),低层模块实现高层模块声明的接口。这样控制权在父类(高层模块),低层模块反而要依赖高层模块。
//Template.h
#ifndef _TEMPLATE_H_
#define _TEMPLATE_H_
class AbstractClass
{
public:
virtual ~AbstractClass();
void TemplateMethod();
protected:
virtual void PrimitiveOperation1() = 0;
virtual void PrimitiveOperation2() = 0;
AbstractClass();
private:
};
class ConcreteClass1:public AbstractClass
{
public:
ConcreteClass1();
~ConcreteClass1();
protected:
void PrimitiveOperation1();
void PrimitiveOperation2();
private:
};
class ConcreteClass2:public AbstractClass
{
public:
ConcreteClass2();
~ConcreteClass2();
protected:
void PrimitiveOperation1();
void PrimitiveOperation2();
private:
};
#endif //~_TEMPLATE_H_
//Template.cpp
#include "Template.h"
#include <iostream>
using namespace std;
AbstractClass::AbstractClass()
{
}
AbstractClass::~AbstractClass()
{
}
void AbstractClass::TemplateMethod()
{
this->PrimitiveOperation1();
this->PrimitiveOperation2();
}
ConcreteClass1::ConcreteClass1()
{
}
ConcreteClass1::~ConcreteClass1()
{
}
void ConcreteClass1::PrimitiveOperation1()
{
cout<<"ConcreteClass1...PrimitiveOperat
ion1"<<endl;
}
void ConcreteClass1::PrimitiveOperation2()
{
cout<<"ConcreteClass1...PrimitiveOperat
ion2"<<endl;
}
ConcreteClass2::ConcreteClass2()
{
}
ConcreteClass2::~ConcreteClass2()
{
}
void ConcreteClass2::PrimitiveOperation1()
{
cout<<"ConcreteClass2...PrimitiveOperat
ion1"<<endl;
}
void ConcreteClass2::PrimitiveOperation2()
{
cout<<"ConcreteClass2...PrimitiveOperat
ion2"<<endl;
}
//main.cpp
#include "Template.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
AbstractClass* p1 = new ConcreteClass1();
AbstractClass* p2 = new ConcreteClass2();
p1->TemplateMethod();
p2->TemplateMethod();
return 0;
}
Strategy Pattern
方案:
Context类用ContextInterface来配置,维护一个对strategy对象的引用;
Strategy类用于定义所有支持算法的接口;
子类则封装了具体的算法实现;
Strategy Pattern 定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
Code:
//strategy.h
#ifndef _STRATEGY_H_
#define _STRATEGY_H_
class Strategy
{
public:
Strategy();
virtual ~Strategy();
virtual void AlgrithmInterface() = 0;
protected:
private:
};
class ConcreteStrategyA:public Strategy
{
public:
ConcreteStrategyA();
virtual ~ConcreteStrategyA();
void AlgrithmInterface();
protected:
private:
};
class ConcreteStrategyB:public Strategy
{
public:
ConcreteStrategyB();
virtual ~ConcreteStrategyB();
void AlgrithmInterface();
protected:
private:
};
#endif //~_STRATEGY_H_
//Strategy.cpp
#include "Strategy.h"
#include <iostream>
using namespace std;
Strategy::Strategy()
{
}
Strategy::~Strategy()
{
cout<<"~Strategy....."<<endl;
}
void Strategy::AlgrithmInterface()
{
}
ConcreteStrategyA::ConcreteStrategyA()
{
}
ConcreteStrategyA::~ConcreteStrategyA()
{
cout<<"~ConcreteStrategyA....."<<endl;
}
void ConcreteStrategyA::AlgrithmInterface()
{
cout<<"test ConcreteStrategyA....."<<endl;
}
ConcreteStrategyB::ConcreteStrategyB()
{
}
ConcreteStrategyB::~ConcreteStrategyB()
{
cout<<"~ConcreteStrategyB....."<<endl;
}
void ConcreteStrategyB::AlgrithmInterface()
{
cout<<"test ConcreteStrategyB....."<<endl;
}
//Context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
class Strategy;
/*
这个类是 Strategy 模式的关键,也是 Strategy 模式和 Template 模式的根本区别所在。
Strategy 通过“组合”(委托)方式实现算法(实现)的异构,而 Template 模式则采取的是继承的方式,这两个模式的区别也是继承和组合两种实现接口重用的方式的区别.
*/
class Context
{
public:
Context(Strategy* stg);
~Context();
void DoAction();
protected:
private:
Strategy* _stg;
};
#endif //~_CONTEXT_H_
//Client.c
//Context.cpp
#include "Context.h"
#include "Strategy.h"
#include <iostream>
using namespace std;
Context::Context(Strategy* stg)
{
_stg = stg;
}
Context::~Context()
{
if (!_stg)
delete _stg;
}
void Context::DoAction()
{
_stg->AlgrithmInterface();
}
//main.cpp
#include "Context.h"
#include "Strategy.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Strategy* ps = new ConcreteStrategyA();
Context* pc = new Context(ps);
pc->DoAction();
if (NULL != pc)
delete pc;
return 0;
}
State Pattern
问题:
- 状态的数目不是很多的时候,switch/case 或许已经能够解决问题了,但是当状态数目非常多的时候,上述的方法就非常难以维护了。
- 状态逻辑和动作的实际实现没有分离,系统的扩展性和维护效率低下;
方案:
把状态的判断逻辑转移到表示不同状态的一系列类中,将复杂的判断逻辑简化;
-
首先构造一个状态类虚基类State 用于封装接口,不同的状态类(ConcreteStateA, ConcreteStateB)继承自State类;
-
Context 类是供Client调用的,含有一个State成员代表状态对象,并封装对外职能接口State->operationInterface,同时包含private的状态切换方法 ChangeState:以state为参数,将context的state成员更改为新的状态对象,因为供state调用,这里需要将state声明为友元类。另外还会对外公开一个无参的OperationChangState方法,实现状态切换的动作;
-
因为每个状态子类知道自己的状态ConcreteStateA和下一个状态ConcreteStateB,所以state类有成员函数ChangeState,参数是contex和state,功能是去修改context的state成员代表的子类对象;当用户调用context的OperationChangState方法时,方法内部调用state的ChangeState,将this指针传入,state持有context并创建下一状态的对象,再调用contex私有状态更新方法ChangeState,将context的state成员修改为指向下一状态对象ConcreteStateB。
Code:
//state.h
#ifndef _STATE_H_
#define _STATE_H_
class Context; //前置声明
class State
{
public:
State();
virtual ~State();
virtual void OperationInterface(Context* ) = 0;
virtual void OperationChangeState(Context*) = 0;
protected:
bool ChangeState(Context* con,State* st);
private:
//bool ChangeState(Context* con,State* st);
};
class ConcreteStateA:public State
{
public:
ConcreteStateA();
virtual ~ConcreteStateA();
virtual void OperationInterface(Context* );
virtual void OperationChangeState(Context*);
protected:
private:
};
class ConcreteStateB:public State
{
public:
ConcreteStateB();
virtual ~ConcreteStateB();
virtual void OperationInterface(Context* );
virtual void OperationChangeState(Context*);
protected:
private:
};
#endif //~_STATE_H_
//State.cpp
#include "State.h"
#include "Context.h"
#include <iostream>
using namespace std;
State::State()
{
}
State::~State()
{
}
void State::OperationInterface(Context* con)
{
cout<<"State::.."<<endl;
}
bool State::ChangeState(Context* con,State* st)
{
con->ChangeState(st);
return true;
}
void State::OperationChangeState(Context* con)
{
}
///
ConcreteStateA::ConcreteStateA()
{
}
ConcreteStateA::~ConcreteStateA()
{
}
void ConcreteStateA::OperationInterface(Context* con)
{
cout<<"ConcreteStateA::OperationInterface
......"<<endl;
}
void ConcreteStateA::OperationChangeState(Context* con)
{
OperationInterface(con);
this->ChangeState(con,new ConcreteStateB());
}
///
ConcreteStateB::ConcreteStateB()
{
}
ConcreteStateB::~ConcreteStateB()
{
}
void ConcreteStateB::OperationInterface(Context* con)
{
cout<<"ConcreteStateB::OperationInterface......"<<endl;
}
void ConcreteStateB::OperationChangeState(Context* con)
{
OperationInterface(con);
this->ChangeState(con,new ConcreteStateA());
}
//context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
class State;
/**
*
**/
class Context
{
public:
Context();
Context(State* state);
~Context();
void OprationInterface();
void OperationChangState();
protected:
private:
friend class State; //表明在 State 类中可以访问 Context 类的 private 字段
bool ChangeState(State* state);
private:
State* _state;
};
#endif //~_CONTEXT_H_
//context.cpp
#include "Context.h"
#include "State.h"
Context::Context()
{
}
Context::Context(State* state)
{
this->_state = state;
}
Context::~Context()
{
delete _state;
}
void Context::OprationInterface()
{
_state->OperationInterface(this);
}
bool Context::ChangeState(State* state)
{
///_state->ChangeState(this,state);
this->_state = state;
return true;
}
void Context::OperationChangState()
{
_state->OperationChangeState(this);
}
//main.cpp
#include "Context.h"
#include "State.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
State* st = new ConcreteStateA();
Context* con = new Context(st);
con->OperationChangState();
con->OperationChangState();
con->OperationChangState();
if (con != NULL)
delete con;
if (st != NULL)
st = NULL;
return 0;
}
Observer Pattern
问题:
建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变。
方案:
这里的目标 Subject 提供依赖于它的观察者 Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。观察者 Observer 则提供一个 Update 操作,注意这里的 Observer 的 Update 操作并不在 Observer 改变了 Subject 目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有Observer 进行修改(调用 Update)。
当一个对象的改变同时引起其他多个对象的时候考虑使用观察者模式。
观察者模式重点在于解耦合,让耦合的双方均依赖于抽象,而不是具体,使得各自的变化不会影响到另一边的变化。
Code:
//Subject.h
#ifndef _SUBJECT_H_
#define _SUBJECT_H_
#include <list>
#include <string>
using namespace std;
typedef string State;
class Observer;
class Subject
{
public:
virtual ~Subject();
virtual void Attach(Observer* obv);
virtual void Detach(Observer* obv);
virtual void Notify();
virtual void SetState(const State& st) = 0;
virtual State GetState() = 0;
protected:
Subject();
private:
list<Observer* >* _obvs;
};
class ConcreteSubject:public Subject
{
public:
ConcreteSubject();
~ConcreteSubject();
State GetState();
void SetState(const State& st);
protected:
private:
State _st;
};
#endif //~_SUBJECT_H_
//Subject.cpp
#include "Subject.h"
#include "Observer.h"
#include <iostream>
#include <list>
using namespace std;
typedef string state;
Subject::Subject()
{
//****在模板的使用之前一定要 new,创建
_obvs = new list<Observer*>;
}
Subject::~Subject()
{
}
void Subject::Attach(Observer* obv)
{
_obvs->push_front(obv);
}
void Subject::Detach(Observer* obv)
{
if (obv != NULL)
_obvs->remove(obv);
}
void Subject::Notify()
{
list<Observer*>::iterator it;
it = _obvs->begin();
for (;it != _obvs->end();it++)
{
//关于模板和 iterator 的用法
(*it)->Update(this);
}
}
ConcreteSubject::ConcreteSubject()
{
_st = '\0';
}
ConcreteSubject::~ConcreteSubject()
{
}
State ConcreteSubject::GetState()
{
return _st;
}
void ConcreteSubject::SetState(const State& st)
{
_st = st;
}
//Observer.h
#ifndef _OBSERVER_H_
#define _OBSERVER_H_
#include "Subject.h"
#include <string>
using namespace std;
typedef string State;
class Observer
{
public:
virtual ~Observer();
virtual void Update(Subject* sub) = 0;
virtual void PrintInfo() = 0;
protected:
Observer();
State _st;
private:
};
class ConcreteObserverA:public Observer
{
public:
virtual Subject* GetSubject();
ConcreteObserverA(Subject* sub);
virtual ~ConcreteObserverA();
//传入 Subject 作为参数,这样可以让一个 View 属于多个的 Subject。
void Update(Subject* sub);
void PrintInfo();
protected:
private:
Subject* _sub;
};
class ConcreteObserverB:public Observer
{
public:
virtual Subject* GetSubject();
sConcreteObserverB(Subject* sub);
virtual ~ConcreteObserverB();
//传入 Subject 作为参数,这样可以让一个 View 属于多个的 Subject。
void Update(Subject* sub);
void PrintInfo();
protected:
private:
Subject* _sub;
};
#endif //~_OBSERVER_H_
//Observer.cpp
#include "Observer.h"
#include "Subject.h"
#include <iostream>
#include <string>
using namespace std;
Observer::Observer()
{
_st = '\0';
}
Observer::~Observer()
{
}
ConcreteObserverA::ConcreteObserverA(Subject* sub)
{
_sub = sub;
_sub->Attach(this);
}
ConcreteObserverA::~ConcreteObserverA()
{
_sub->Detach(this);
if (_sub != 0)
{
delete _sub;
}
}
Subject* ConcreteObserverA::GetSubject()
{
return _sub;
}
void ConcreteObserverA::PrintInfo()
{
cout<<"ConcreteObserverA observer....
"<<_sub->GetState()<<endl;
}
void ConcreteObserverA::Update(Subject* sub)
{
_st = sub->GetState();
PrintInfo();
}
ConcreteObserverB::ConcreteObserverB(Subject* sub)
{
_sub = sub;
_sub->Attach(this);
}
ConcreteObserverB::~ConcreteObserverB()
{
_sub->Detach(this);
if (_sub != 0)
{
delete _sub;
}
}
Subject* ConcreteObserverB::GetSubject()
{
return _sub;
}
void ConcreteObserverB::PrintInfo()
{
cout<<"ConcreteObserverB observer....
"<<_sub->GetState()<<endl;
}
void ConcreteObserverB::Update(Subject* sub)
{
_st = sub->GetState();
PrintInfo();
}
//main.cpp
#include "Subject.h"
#include "Observer.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
ConcreteSubject* sub = new ConcreteSubject();
Observer* o1 = new ConcreteObserverA(sub);
Observer* o2 = new ConcreteObserverB(sub);
sub->SetState("old");
sub->Notify();
sub->SetState("new"); //也可以由 Observer 调用
sub->Notify();
return 0;
}
Memento Pattern
问题:
撤销操作(Undo)的支持,在不破坏封装的前提下,捕获一个内部状态,在对象之外保存,这样可以利用保存的状态实现恢复操作。
方案:
Code:
//Memento.h
#ifndef _MEMENTO_H_
#define _MEMENTO_H_
#include <string>
using namespace std;
class Memento;
class Originator
{
public:
typedef string State;
Originator();
Originator(const State& sdt);
~Originator();
Memento* CreateMemento();
void SetMemento(Memento* men);
void RestoreToMemento(Memento* mt);
State GetState();
void SetState(const State& sdt);
void PrintState();
protected:
private:
State _sdt;
Memento* _mt;
};
class Memento
{
public:
protected:
private:
//这是最关键的地方,将 Originator 为 friend 类,可以访问内部信息,但是其
//他类不能访问
friend class Originator;
typedef string State;
Memento();
Memento(const State& sdt);
~Memento();
void SetState(const State& sdt);
State GetState();
private:
State _sdt;
};
#endif //~_MEMENTO_H_
//Memento.cpp
#include "Memento.h"
#include <iostream>
using namespace std;
typedef string State;
Originator::Originator()
{
_sdt = "";
_mt = 0;
}
Originator::Originator(const State& sdt)
{
_sdt = sdt;
_mt = 0;
}
Originator::~Originator()
{
}
Memento* Originator::CreateMemento()
{
return new Memento(_sdt);
}
State Originator::GetState()
{
return _sdt;
}
void Originator::SetState(const State& sdt)
{
_sdt = sdt;
}
void Originator::PrintState()
{
cout<<this->_sdt<<"....."<<endl;
}
void Originator::SetMemento(Memento* men)
{
}
void Originator::RestoreToMemento(Memento* mt)
{
this->_sdt = mt->GetState();
}
//class Memento
Memento::Memento()
{
}
Memento::Memento(const State& sdt)
{
_sdt = sdt;
}
State Memento::GetState()
{
return _sdt;
}
void Memento::SetState(const State& sdt)
{
_sdt = sdt;
}
//main.cpp
#include "Memento.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Originator* o = new Originator();
o->SetState("old"); //备忘前状态
o->PrintState();
Memento* m = o->CreateMemento(); //将状态备忘
o->SetState("new"); //修改状态
o->PrintState();
o->RestoreToMemento(m);
//恢复修改前状态
o->PrintState();
return 0;
}
Mediator Pattern
问题:
对象之间的交互和通讯的封装,因为大量的连接使得一个对象不可能在没有其他对象的支持下工作,系统表现为一个不可分割的整体,造成系统各模块之间的耦合较强。
迪米特法则 如果两个类之间不必彼此之间直接通讯,那么这两个类不应当发生直接的相互作用,如果一个类需要调用另一个类的某个方法,可以通过第三者转发这个调用。
方案:
Mediator 模式中,每个 Colleague 维护一个 Mediator,当要进行交互,例如图中
ConcreteColleagueA 和 ConcreteColleagueB 之间的交互就可以通过 ConcreteMediator 提供的DoActionFromAtoB 来处理, ConcreteColleagueA 和 ConcreteColleagueB 不必维护对各自的引用,甚至它们也不知道各个的存在。Mediator 通过这种方式将多对多的通信简化为了一(Mediator)对多(Colleague)的通信。
Code
//Colleage.h
#ifndef _COLLEAGE_H_
#define _COLLEAGE_H_
#include <string>
using namespace std;
class Mediator;
class Colleage
{
public:
virtual void Aciton() = 0;
virtual void SetState(const string& sdt) = 0;
virtual string GetState() = 0;
protected:
Colleage();
Colleage(Mediator* mdt);
Mediator* _mdt;
private:
};
class ConcreteColleageA:public Colleage
{
public:
ConcreteColleageA();
ConcreteColleageA(Mediator* mdt);
~ConcreteColleageA();
void Aciton();
void SetState(const string& sdt);
string GetState();
protected:
private:
string _sdt;
};
class ConcreteColleageB:public Colleage
{
public:
ConcreteColleageB();
ConcreteColleageB(Mediator* mdt);
~ConcreteColleageB();
void Aciton();
void SetState(const string& sdt);
string GetState();
protected:
private:
string _sdt;
};
#endif //~_COLLEAGE_H_
//Colleage.cpp
#include "Mediator.h"
#include "Colleage.h"
#include <iostream>
using namespace std;
Colleage::Colleage()
{
//_sdt = " ";
}
Colleage::Colleage(Mediator* mdt)
{
this->_mdt = mdt;
//_sdt = " ";
}
Colleage::~Colleage()
{
}
ConcreteColleageA::ConcreteColleageA()
{
}
ConcreteColleageA::~ConcreteColleageA()
{
}
ConcreteColleageA::ConcreteColleageA(Mediator* mdt):Colleage(mdt)
{
}
string ConcreteColleageA::GetState()
{
return _sdt;
}
void ConcreteColleageA::SetState(const string& sdt)
{
_sdt = sdt;
}
void ConcreteColleageA::Aciton()
{
_mdt->DoActionFromAtoB();
cout<<"State of ConcreteColleageB:"<<"
"<<this->GetState()<<endl;
}
ConcreteColleageB::ConcreteColleageB()
{
}
ConcreteColleageB::~ConcreteColleageB()
{
}
ConcreteColleageB::ConcreteColleageB(Mediator*mdt):Colleage(mdt)
{
}
void ConcreteColleageB::Aciton()
{
_mdt->DoActionFromBtoA();
cout<<"State of ConcreteColleageB:"<<"
"<<this->GetState()<<endl;
}
string ConcreteColleageB::GetState()
{
return _sdt;
}
void ConcreteColleageB::SetState(const string& sdt)
{
_sdt = sdt;
}
//Mediator.h
#ifndef _MEDIATOR_H_
#define _MEDIATOR_H_
class Colleage;
class Mediator
{
public:
virtual ~Mediator();
virtual void DoActionFromAtoB() = 0;
virtual void DoActionFromBtoA() = 0;
protected:
Mediator();
private:
};
class ConcreteMediator:public Mediator
{
public:
ConcreteMediator();
ConcreteMediator(Colleage* clgA,Colleage* clgB);
~ConcreteMediator();
void SetConcreteColleageA(Colleage* clgA);
void SetConcreteColleageB(Colleage* clgB);
Colleage* GetConcreteColleageA();
Colleage* GetConcreteColleageB();
void IntroColleage(Colleage* clgA,Colleage* clgB);
void DoActionFromAtoB();
void DoActionFromBtoA();
protected:
private:
Colleage* _clgA;
Colleage* _clgB;
};
#endif //~_MEDIATOR_H_
//Mediator.cpp
#include "Mediator.h"
#include "Colleage.h"
Mediator::Mediator()
{
}
Mediator::~Mediator()
{
}
ConcreteMediator::ConcreteMediator()
{
}
ConcreteMediator::~ConcreteMediator()
{
}
ConcreteMediator::ConcreteMediator(Colleage* clgA,Colleage* clgB)
{
this->_clgA = clgA;
this->_clgB = clgB;
}
void ConcreteMediator::DoActionFromAtoB()
{
_clgB->SetState(_clgA->GetState());
}
void ConcreteMediator::SetConcreteColleageA(Colleage* clgA)
{
this->_clgA = clgA;
}
void ConcreteMediator::SetConcreteColleageB(Colleage* clgB)
{
this->_clgB = clgB;
}
Colleage* ConcreteMediator::GetConcreteColleageA()
{
return _clgA;
}
Colleage* ConcreteMediator::GetConcreteColleageB()
{
return _clgB;
}
void ConcreteMediator::IntroColleage(Colleage* clgA,Colleage* clgB)
{
this->_clgA = clgA;
this->_clgB = clgB;
}
void ConcreteMediator::DoActionFromBtoA()
{
_clgA->SetState(_clgB->GetState());
}
//main.cpp
#include "Mediator.h"
#include "Colleage.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
ConcreteMediator* m = new ConcreteMediator();
ConcreteColleageA* c1 = new ConcreteColleageA(m);
ConcreteColleageB* c2 = new ConcreteColleageB(m);
m->IntroColleage(c1,c2);
c1->SetState("old");
c2->SetState("old");
c1->Aciton();
c2->Aciton();
cout<<endl;
c1->SetState("new");
c1->Aciton();
c2->Aciton();
cout<<endl;
c2->SetState("old");
c2->Aciton();
c1->Aciton();
return 0;
}
总结:
由于中介者模式将对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,这样关注的对象就从对象各自本身的行为转移到对象之间的交互上来,也就站在更高的角度去看系统,由于中介对象将对象之间交互的复杂性转移到中介对象内部复杂性,使得中介者对象本身复杂性提高。
Command Pattern
问题:
通过将请求封装到一个对象Command中,并将请求的接受者存放在具体的ConcreteCommand类中(Receiver)中,从而实现调用操作的对象的具体实现者之间的解耦。
方案:
Command 模式结构图中,将请求的接收者(处理者)放到 Command 的具体子类ConcreteCommand 中,当请求到来时(Invoker 发出 Invoke 消息激活 Command 对象),ConcreteCommand 将处理请求交给 Receiver 对象进行处理。
Code:
//Reciever.h
#ifndef _RECIEVER_H_
#define _RECIEVER_H_
class Reciever
{
public:
Reciever();
~Reciever();
void Action();
protected:
private:
};
#endif //~_RECIEVER_H_
//Reciever.cpp
#include "Reciever.h"
#include <iostream>
Reciever::Reciever()
{
}
Reciever::~Reciever()
{
}
void Reciever::Action()
{
std::cout<<"Reciever action......."<<std::endl;
}
//Command.h
#ifndef _COMMAND_H_
#define _COMMAND_H_
class Reciever;
class Command
{
public:
virtual ~Command();
virtual void Excute() = 0;
protected:
Command();
private:
};
class ConcreteCommand:public Command
{
public:
ConcreteCommand(Reciever* rev);
~ConcreteCommand();
void Excute();
protected:
private:
Reciever* _rev;
};
#endif //~_COMMAND_H_
//Command.cpp
#include "Command.h"
#include "Reciever.h"
#include <iostream>
Command::Command()
{
}
Command::~Command()
{
}
void Command::Excute()
{
}
ConcreteCommand::ConcreteCommand(Reciever* rev)
{
this->_rev = rev;
}
ConcreteCommand::~ConcreteCommand()
{
delete this->_rev;
}
void ConcreteCommand::Excute()
{
_rev->Action();
std::cout<<"ConcreteCommand..."<<std::endl;
}
//Invoker.h
#ifndef _INVOKER_H_
#define _INVOKER_H_
class Command;
class Invoker
{
public:
Invoker(Command* cmd);
~Invoker();
void Invoke();
protected:
private:
Command* _cmd;
};
#endif //~_INVOKER_H_
//Invoker.cpp
#include "Invoker.h"
#include "Command.h"
#include <iostream>
Invoker::Invoker(Command* cmd)
{
_cmd = cmd;
}
Invoker::~Invoker()
{
delete _cmd;
}
void Invoker::Invoke()
{
_cmd->Excute();
}
//main.cpp
#include "Command.h"
#include "Invoker.h"
#include "Reciever.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Reciever* rev = new Reciever();
Command* cmd = new ConcreteCommand(rev);
Invoker* inv = new Invoker(cmd);
inv->Invoke();
return 0;
}
总结:
命令模式把请求一个操作的对象与知道怎么执行一个操作对象分隔开;
比较容易设计一个命令队列;
在有需要的情况下,可以将命令记录进日志;
允许接受请求的一方决定是否否决请求;
可以实现对请求的撤销和重做;
由于加进新的具体命令类不会影响其他的类,扩展新的命令类很容易;
敏捷开发告诉我们,不要为代码添加基于猜测的,实际不需要的功能,如果不清楚一个系统是否需要命令模式,一般不需要去实现,实际上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复的功能时,搭建这个结构才有意义。
Visitor Pattern
问题:
将变更封装进一个类中,并由待更改类提供一个接收接口;
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
方案:
Visitor 模式在不破坏类的前提下,为类提供增加新的新操作。Visitor 模式的关键是双分派(Double-Dispatch)的技术。C++语言支持的是单分派。
双分派意味着执行的操作将取决于请求的种类和接收者的类型。
在 Visitor 模式中 Accept()操作是一个双分派的操作。具体调用哪一个具体的 Accept()操作,有两个决定因素:
1)Element 的类型。因为 Accept()是多态的操作,需要具体的 Element 类型的子类才可以决定到底调用哪一个 Accept()实现;
2)Visitor 的类型。Accept()操作有一个参数(Visitor* vis),要决定了实际传进来的 Visitor 的实际类别才可以决定具体是调用哪个 VisitConcrete()实现。
Code:
//Visitor.h
#ifndef _VISITOR_H_
#define _VISITOR_H_
class ConcreteElementA;
class ConcreteElementB;
class Element;
class Visitor
{
public:
virtual ~Visitor();
virtual void VisitConcreteElementA(Element* elm) = 0;
virtual void VisitConcreteElementB(Element* elm) = 0;
protected:
Visitor();
private:
};
class ConcreteVisitorA:public Visitor
{
public:
ConcreteVisitorA();
virtual ~ConcreteVisitorA();
virtual void VisitConcreteElementA(Element* elm);
virtual void VisitConcreteElementB(Element* elm);
protected:
private:
};
class ConcreteVisitorB:public Visitor
{
public:
ConcreteVisitorB();
virtual ~ConcreteVisitorB();
virtual void VisitConcreteElementA(Element* elm);
virtual void VisitConcreteElementB(Element* elm);
protected:
private:
};
#endif //~_VISITOR_H_
//Visitor.cpp
#include "Visitor.h"
#include "Element.h"
#include <iostream>
using namespace std;
Visitor::Visitor()
{
}
Visitor::~Visitor()
{
}
ConcreteVisitorA::ConcreteVisitorA()
{
}
ConcreteVisitorA::~ConcreteVisitorA()
{
}
void ConcreteVisitorA::VisitConcreteElementA(Element* elm)
{
cout<<"i will visit ConcreteElementA..."<<endl;
}
void ConcreteVisitorA::VisitConcreteElementB(Element* elm)
{
cout<<"i will visit ConcreteElementB..."<<endl;
}
ConcreteVisitorB::ConcreteVisitorB()
{
}
ConcreteVisitorB::~ConcreteVisitorB()
{
}
void ConcreteVisitorB::VisitConcreteElementA(Element* elm)
{
cout<<"i will visit ConcreteElementA..."<<endl;
}
void ConcreteVisitorB::VisitConcreteElementB(Element* elm)
{
cout<<"i will visit ConcreteElementB..."<<endl;
}
//Element.h
#ifndef _ELEMENT_H_
#define _ELEMENT_H_
class Visitor;
class Element
{
public:
virtual ~Element();
virtual void Accept(Visitor* vis) = 0;
protected:
Element();
private:
};
class ConcreteElementA:public Element
{
public:
ConcreteElementA();
~ConcreteElementA();
void Accept(Visitor* vis);
protected:
private:
};
class ConcreteElementB:public Element
{
public:
ConcreteElementB();
~ConcreteElementB();
void Accept(Visitor* vis);
protected:
private:
};
#endif //~_ELEMENT_H_
//Element.cpp
#include "Element.h"
#include "Visitor.h"
#include <iostream>
using namespace std;
Element::Element()
{
}
Element::~Element()
{
}
void Element::Accept(Visitor* vis)
{
}
ConcreteElementA::ConcreteElementA()
{
}
ConcreteElementA::~ConcreteElementA()
{
}
void ConcreteElementA::Accept(Visitor* vis)
{
vis->VisitConcreteElementA(this);
cout<<"visiting ConcreteElementA..."<<endl;
}
ConcreteElementB::ConcreteElementB()
{
}
ConcreteElementB::~ConcreteElementB()
{
}
void ConcreteElementB::Accept(Visitor* vis)
{
cout<<"visiting ConcreteElementB..."<<endl;
vis->VisitConcreteElementB(this);
}
#include "Element.h"
#include "Visitor.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Visitor* vis = new ConcreteVisitorA();
Element* elm = new ConcreteElementA();
elm->Accept(vis);
return 0;
}
总结:
1)Visitor 类中的 Visit()操作的实现。
- 这里我们可以向 Element 类仅仅提供一个接口 Visit(),而在 Accept()实现中具 体调用哪一个 Visit()操作则通过函数重载(overload)的方式实现:我们提供 Visit ()的两个重载版本
a) Visit(ConcreteElementA* elmA),
b) Visit (ConcreteElementB* elmB)。 ‹ - 在C++中我们还可以通过 RTTI(运行时类型识别:Runtime type identification)来实现,即我们只提供一个Visit()函数体,传入的参数为 Element*型别参数 ,然 后用 RTTI 决定具体是哪一类的 ConcreteElement参数,再决定具体要对哪个具体类施加什么样的具体操作。
【注释】RTTI 给接口带来了简单一致性,但是付出的代价是时间(RTTI 的实现)和代码的 Hard 编码(要进行强制转换)。
Visitor 模式可以使得 Element 在不修改自己的同时增加新的操作,但是这也带来了至少
以下的两个显著问题:
- 破坏了封装性。Visitor 模式要求 Visitor 可以从外部修改 Element 对象的状态,这一般通过两个方式来实现:
a)Element 提供足够的 public 接口,使得 Visitor 可以通过调用这些接口达到修改 Element 状态的目的;
b) Element 暴露更多的细节给 Visitor,或者让 Element 提供 public 的实现给 Visitor (当然也给了系统中其他的对象),或者将 Visitor 声明为 Element 的 friend 类,仅将细节暴露给 Visitor。
但是无论那种情况,特别是后者都将是破坏了封装性原则(实际上就是 C++的 friend 机制得到了很多的面向对象专家的诟病)。 - ConcreteElement 的扩展很困难:每增加一个 Element 的子类,就要修改 Visitor 的接口,使得可以提供给这个新增加的子类的访问机制。从上面我们可以看到,或者增加一个用于处理新增类的 Visit()接口,或者重载一个处理新增类的 Visit()操作,或者要修改 RTTI 方式实现的 Visit ()实现。无论那种方式都给扩展新的 Element子类带来了困难。
Chain of Responsibility
问题:
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系关系。将这个对象连成一条链,并沿着这条链条传递该请求,直到有一个对象处理它为止。
方案:
Chain of Responsibility 模式中 ConcreteHandler 将自己的后继对象(向下传递消息的对象)记录在自己的后继表中,当一个请求到来时,ConcreteHandler 会先检查看自己有没有匹配的处理程序,如果有就自己处理,否则传递给它的后继。当然这里示例程序中为了简化,ConcreteHandler 只是简单的检查看自己有没有后继,有的话将请求传递给后继进行处理,没有的话就自己处理。
Code:
//Handle.h
#ifndef _HANDLE_H_
#define _HANDLE_H_
class Handle
{
public:
virtual ~Handle();
virtual void HandleRequest() = 0;
void SetSuccessor(Handle* succ);
Handle* GetSuccessor();
protected:
Handle();
Handle(Handle* succ);
private:
Handle* _succ;
};
class ConcreteHandleA:public Handle
{
public:
ConcreteHandleA();
~ConcreteHandleA();
ConcreteHandleA(Handle* succ);
void HandleRequest();
protected:
private:
};
class ConcreteHandleB:public Handle
{
public:
ConcreteHandleB();
~ConcreteHandleB();
ConcreteHandleB(Handle* succ);
void HandleRequest();
protected:
private:
};
#endif //~_HANDLE_H_
//Handle.cpp
#include "Handle.h"
#include <iostream>
using namespace std;
Handle::Handle()
{
_succ = 0;
}
Handle::~Handle()
{
delete _succ;
}
Handle::Handle(Handle* succ)
{
this->_succ = succ;
}
void Handle::SetSuccessor(Handle* succ)
{
_succ = succ;
}
Handle* Handle::GetSuccessor()
{
return _succ;
}
void Handle::HandleRequest()
{
}
ConcreteHandleA::ConcreteHandleA()
{
}
ConcreteHandleA::ConcreteHandleA(Handle* succ):Handle(succ)
{
}
ConcreteHandleA::~ConcreteHandleA()
{
}
void ConcreteHandleA::HandleRequest()
{
if (this->GetSuccessor() != 0)
{
cout<<"ConcreteHandleA 我把处理权给后继节点....."<<endl;
this->GetSuccessor()->HandleRequest();
}
else
{
cout<<"ConcreteHandleA 没有后继了,我必须自己处理...."<<endl;
}
}
ConcreteHandleB::ConcreteHandleB()
{
}
ConcreteHandleB::ConcreteHandleB(Handle* succ):Handle(succ)
{
}
ConcreteHandleB::~ConcreteHandleB()
{
}
void ConcreteHandleB::HandleRequest()
{
if (this->GetSuccessor() != 0)
{
cout<<"ConcreteHandleB 我把处理权给后继节点....."<<endl;
this->GetSuccessor()->HandleRequest();
}
else
{
cout<<"ConcreteHandleB 没有后继了,我必须自己处理...."<<endl;
}
}
//main.cpp
#include "Handle.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Handle* h1 = new ConcreteHandleA();
Handle* h2 = new ConcreteHandleB();
h1->SetSuccessor(h2);
h1->HandleRequest();
return 0;
}
总结:
ConcreteHandleA 的对象和 h1 拥有一个后继 ConcreteHandleB 的对象 h2,当一个请求到来时候,h1 检查看自己有后继,于是 h1 直接将请求传递给其后继 h2 进行处理,h2 因为没有后继,当请求到来时候,就只有自己提供响应了。于是程序的输出为:
- ConcreteHandleA 我把处理权给后继节点…;
- ConcreteHandleB没有后继了,我必须自己处理…。
Iterator Pattern
问题:
提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
方案:
Code:
//Aggregate.h
#ifndef _AGGREGATE_H_
#define _AGGREGATE_H_
class Iterator;
typedef int Object;
class Interator;
class Aggregate
{
public:
virtual ~Aggregate();
virtual Iterator* CreateIterator() = 0;
virtual Object GetItem(int idx) = 0;
virtual int GetSize() = 0;
protected:
Aggregate();
private:
};
class ConcreteAggregate:public Aggregate
{
public:
enum {SIZE = 3};
ConcreteAggregate();
~ConcreteAggregate();
Iterator* CreateIterator();
Object GetItem(int idx);
int GetSize();
protected:
private:
Object _objs[SIZE];
};
#endif //~_AGGREGATE_H_
//Aggregate.cpp
#include "Aggregate.h"
#include "Iterator.h"
#include <iostream>
using namespace std;
Aggregate::Aggregate()
{
}
Aggregate::~Aggregate()
{
}
ConcreteAggregate::ConcreteAggregate()
{
for (int i = 0; i < SIZE; i++)
_objs[i] = i;
}
ConcreteAggregate::~ConcreteAggregate()
{
}
Iterator* ConcreteAggregate::CreateIterator()
{
return new ConcreteIterator(this);
}
Object ConcreteAggregate::GetItem(int idx)
{
if (idx < this->GetSize())
return _objs[idx];
else
return -1;
}
int ConcreteAggregate::GetSize()
{
return SIZE;
}
//Iterator.h
#ifndef _ITERATOR_H_
#define _ITERATOR_H_
class Aggregate;
typedef int Object;
class Iterator
{
public:
virtual ~Iterator();
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() = 0;
virtual Object CurrentItem() = 0;
protected:
Iterator();
private:
};
class ConcreteIterator:public Iterator
{
public:
ConcreteIterator(Aggregate* ag , int idx = 0);
~ConcreteIterator();
void First();
void Next();
bool IsDone();
Object CurrentItem();
protected:
private:
Aggregate* _ag;
int _idx;
};
#endif //~_ITERATOR_H_
//Iterator.cpp
#include "Iterator.h"
#include "Aggregate.h"
#include <iostream>
using namespace std;
Iterator::Iterator()
{
}
Iterator::~Iterator()
{
}
ConcreteIterator::ConcreteIterator(Aggregate* ag , int idx)
{
this->_ag = ag;
this->_idx = idx;
}
ConcreteIterator::~ConcreteIterator()
{
}
Object ConcreteIterator::CurrentItem()
{
return _ag->GetItem(_idx);
}
void ConcreteIterator::First()
{
_idx = 0;
}
void ConcreteIterator::Next()
{
if (_idx < _ag->GetSize())
_idx++;
}
bool ConcreteIterator::IsDone()
{
return (_idx == _ag->GetSize());
}
//main.cpp
#include "Iterator.h"
#include "Aggregate.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Aggregate* ag = new ConcreteAggregate();
Iterator* it = new ConcreteIterator(ag);
for (; !(it->IsDone()) ; it->Next())
{
cout<<it->CurrentItem()<<endl;
}
return 0;
}
Interpreter Pattern
问题:
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表示为一个简单语言的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解释该问题。
例如:正则表达式
所以,通常当有一个语言需要解释执行,并且你可以将该语言中的句子表示为一个抽象语法树时,可以使用解释器模式。
方案:
Code:
//Context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
class Context
{
public:
Context();
~Context();
protected:
private:
};
#endif //~_CONTEXT_H_
//Context.cpp
#include "Context.h"
Context::Context()
{
}
Context::~Context()
{
}
//Interpret.h
#ifndef _INTERPRET_H_
#define _INTERPRET_H_
#include "Context.h"
#include <string>
using namespace std;
class AbstractExpression
{
public:
virtual ~AbstractExpression();
virtual void Interpret(const Context& c);
protected:
AbstractExpression();
private:
};
class TerminalExpression:public AbstractExpression
{
public:
TerminalExpression(const string& statement);
~ TerminalExpression();
void Interpret(const Context& c);
protected:
private:
string _statement;
};
class NonterminalExpression:public AbstractExpression
{
public:
NonterminalExpression(AbstractExpression* expression,int times);
~ NonterminalExpression();
void Interpret(const Context& c);
protected:
private:
AbstractExpression* _expression;
int _times;
};
#endif //~_INTERPRET_H_
//interpret.cpp
#include "Interpret.h"
#include <iostream>
using namespace std;
AbstractExpression::AbstractExpression()
{
}
AbstractExpression::~AbstractExpression()
{
}
void AbstractExpression::Interpret(const Context& c)
{
}
TerminalExpression::TerminalExpression(const string& statement)
{
this->_statement = statement;
}
TerminalExpression::~TerminalExpression()
{
}
void TerminalExpression::Interpret(const Context& c)
{
cout<<this->_statement<<" TerminalExpression"<<endl;
}
NonterminalExpression::NonterminalExpression(AbstractExpression* expression,int times)
{
this->_expression = expression;
this->_times = times;
}
NonterminalExpression::~NonterminalExpression()
{
}
void NonterminalExpression::Interpret(const Context& c)
{
for (int i = 0; i < _times ; i++)
{
this->_expression->Interpret(c);
}
}
//main.cpp
#include "Context.h"
#include "Interpret.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Context* c = new Context();
AbstractExpression* te = new TerminalExpression("hello");
AbstractExpression* nte = new NonterminalExpression(te,2);
nte->Interpret(*c);
return 0;
}
总结:
XML 格式的数据解析是一个在应用开发中很常见并且有时候是很难处理的事情,虽然目前很多的开发平台、语言都提供了对 XML 格式数据的解析,但是例如到了移动终端设备上,由于处理速度、计算能力、存储容量的原因解析 XML 格式的数据却是很复杂的一件事情,最近也提出了很多的移动设备的 XML 格式解析器,但是总体上在项目开发时候还是需要自己去设计和实现这一个过程(笔者就有过这个方面的痛苦经历)。Interpreter 模式则提供了一种很好的组织和设计这种解析器的架构。Interpreter 模式中使用类来表示文法规则,因此可以很容易实现文法的扩展。另外对于终结符我们可以使用 Flyweight 模式来实现终结符的共享。
大裤衩儿 发布了14 篇原创文章 · 获赞 0 · 访问量 615 私信 关注