设计模式之命令模式(Command)摘录
Command:(1)、意图: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
(2)、适用性:
A、抽象出待执行的动作以参数化某对象;
B、在不同的时刻指定、排列和执行请求;
C、支持取消操作;
D、支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍;
E、用构建在原语操作上的高层操作构造一个系统。
(3)、优缺点:
A、Command模式将调用操作的对象与知道如何实现该操作的对象解耦;
B、Command是头等的对象。它们可像其他的对象一样被操作和扩展;
C、你可将多个命令装配成一个复合命令;
D、增加新的Command很容易,因为这无需改变已有的类。
(4)、相关模式:
A、Composite模式可被用来实现宏命令;
B、Memento模式可用来保持某个状态,命令用这一状态来取消它的效果;
C、在被放入历史表列前必须被拷贝的命令起到一种原型的作用。
(5)、命令模式:
A、建立命令队列;
B、可以将命令记入日志;
C、接收请求的一方可以拒绝;
D、添加一个新命令类不影响其它类。命令模式把请求一个操作的对象与知道怎么操作一个操作的对象分开。
(6)、Command模式通过将请求封装到一个对象(Command)中,并将请求的接收者存放到具体的ConcreteCommand类中(Receiver),从而实现调用操作的对象和操作的具体实现者之间的解耦。
示例代码1:
#include <iostream> #include <string> #include <vector> using namespace std; //烤肉师傅 class Barbucer { public: void MakeMutton() { cout<<"烤羊肉"<<endl; } void MakeChickenWing() { cout<<"烤鸡翅膀"<<endl; } }; //抽象命令类 class Command { protected: Barbucer* receiver; public: Command(Barbucer* temp) { receiver = temp; } virtual void ExecuteCmd() = 0; }; //烤羊肉命令 class BakeMuttonCmd : public Command { public: BakeMuttonCmd(Barbucer* temp) : Command(temp) {} virtual void ExecuteCmd() { receiver->MakeMutton(); } }; //烤鸡翅 class ChickenWingCmd : public Command { public: ChickenWingCmd(Barbucer* temp) : Command(temp) {} virtual void ExecuteCmd() { receiver->MakeChickenWing(); } }; //服务员类 class Waiter { protected: vector<Command*> m_commandList; public: void SetCmd(Command* temp) { m_commandList.push_back(temp); cout<<"增加定单"<<endl; } //通知执行 void Notify() { vector<Command*>::iterator p = m_commandList.begin(); while (p != m_commandList.end()) { (*p)->ExecuteCmd(); p ++; } } }; //客户端 int main() { //店里添加烤肉师傅、菜单、服务员等顾客 Barbucer* barbucer = new Barbucer(); Command* cmd = new BakeMuttonCmd(barbucer); Command* cmd2 = new ChickenWingCmd(barbucer); Waiter* girl = new Waiter(); //点菜 girl->SetCmd(cmd); girl->SetCmd(cmd2); //服务员通知 girl->Notify(); /*result 增加定单 增加定单 烤羊肉 烤鸡翅膀 */ return 0; } |
示例代码2:
Receiver.h:
#ifndef _RECEIVER_H_ #define _RECEIVER_H_ class Receiver { public: Receiver(); ~Receiver(); void Action(); protected: private: }; #endif//~_RECEIVER_H_ |
Receiver.cpp:
#include "Receiver.h" #include <iostream> Receiver::Receiver() { } Receiver::~Receiver() { } void Receiver::Action() { std::cout<<"Receiver action ..."<<std::endl; } |
Command.h:
#ifndef _COMMAND_H_ #define _COMMAND_H_ class Receiver; class Command { public: virtual ~Command(); virtual void Excute() = 0; protected: Command(); private: }; class ConcreteCommand : public Command { public: ConcreteCommand(Receiver* rev); ~ConcreteCommand(); void Excute(); protected: private: Receiver* _rev; }; #endif//~_COMMAND_H_ |
Command.cpp:
#include "Command.h" #include "Receiver.h" #include <iostream> Command::Command() { } Command::~Command() { } void Command::Excute() { } ConcreteCommand::ConcreteCommand(Receiver* 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_ |
main.cpp:
#include "Command.h" #include "Invoker.h" #include "Receiver.h" #include <iostream> using namespace std; int main() { Receiver* rev = new Receiver(); Command* cmd = new ConcreteCommand(rev); Invoker* inv = new Invoker(cmd); inv->Invoke(); /*result Receiver action ... ConcreteCommand ... */ return 0; } |
命令模式结构图:
设计模式之访问者模式(Visitor)摘录
Visitor:(1)、意图: 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
(2)、适用性:
A、一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
B、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作”污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
C、定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
(3)、优缺点:
A、访问者模式使得易于增加新的操作:访问者使得增加依赖于复杂对象结构的构件的操作变得容易了。仅需增加一个新的访问者即可在一个对象结构上定义一个新的操作。相反,如果每个功能都分散在多个类之上的话,定义新的操作时必须修改每一类。
B、访问者集中相关的操作而分离无关的操作:相关的行为不是分布在定义该对象结构的各个类上,而是集中在一个访问者中。无关行为却被分别放在它们各自的访问者子类中。这就既简化了这些元素的类,也简化了在这些访问者中定义的算法。所有与它的算法相关的数据结构都可以被隐藏在访问者中。
C、增加新的ConcreteElement类很困难:Visitor模式使得难以增加新的Element的子类。每添加一个新的ConcreteElement都要在Visitor中添加一个新的抽象操作,并在每一个ConcreteVisitor类中实现相应的操作。有时可以在Visitor中提供一个缺省的实现,这一实现可以被大多数的ConcreteVisitor继承,但这与其说是一个规律还不如说是一个例外。所以在应用访问者模式时考虑关键的问题是系统的哪个部分会经常变化,是作用于对象结构上的算法呢还是构成该结构的各个对象的类。如果老是有新的ConcreteElement类加入进来的话,Visitor类层次将变得难以维护。在这种情况下,直接在构成该结构的类中定义这些操作可能更容易一些。如果Element类层次是稳定的,而你不断地增加操作或修改算法,访问者模式可以帮助你管理这些改动。
D、通过类层次进行访问:一个迭代器可以通过调用节点对象的特定操作来遍历整个对象结构,同时访问这些对象。但是迭代器不能对具有不同元素类型的对象结构进行操作。
E、累积状态:当访问者访问对象结构中的每一个元素时,它可能会累积状态。如果没有访问者,这一状态将作为额外的参数传递给进行遍历的操作,或者定义为全局变量。
F、破坏封装:访问者无法假定ConcreteElement接口的功能足够强,足以让访问者进行它们的工作。结果是,该模式常常迫使你提供访问元素内部状态的公共操作,这可能会破坏它的封装性。
(4)、相关模式:
A、Composite:访问者可以用于对一个由Composite模式定义的对象结构进行操作。
B、Interpreter:访问者可以用于解释。
(5)、访问者模式适用于数据结构稳定的系统。它把数据结构和作用于数据结构上的操作分离开,使得操作集合。优点:新增加操作很容易,因为增加新操作就相当于增加一个访问者,访问者模式将有关的行为集中到一个访问者对象中。
(6)、Visitor模式在不去破坏类的前提下,为类提供增加新的操作。Visitor模式的关键是双分派(Double-Dispatch)的技术。C++语言支持的是单分派。双分派意味着执行的操作将取决于请求的种类和接收者的类型。
(7)、Visitor模式可以使得Element在不修改自己的同时增加新的操作,但是这也带来了至少以下的两个显著问题:
A、破坏了封装性:Visitor模式要求Visitor可以从外部修改Element对象的状态,这一般通过两个方式来实现。i、Element提供足够的public接口,使得Visitor可以通过调用这些接口达到修改Element状态的目的;ii、Element暴露更多的细节给Visitor,或者让Element提供public的实现给Visitor(当然也给了系统中其它的对象),或者将Visitor声明为Element的friend类,仅将细节暴露给Visitor。但是无论哪种情况,特别是后者都将破坏封装性原则(实际上就是C++的friend机制得到了很多的面向对象专家的诟病)。
B、ConcreteElement的扩展很困难:每增加一个Element的子类,就要修改Visitor的接口,使得可以提供给这个新增加的子类的访问机制。或者增加一个用于处理新增类的visit()接口,或者重载一个处理新增类的visit()操作,或者要修改RTTI(运行时类型识别:Runtime
type identification)方式实现的visit()实现。无论哪种方式都给扩展新的Element子类带来了困难。RTTI给接口带来了简单一致性,但是付出的代价是时间(RTTI的实现)和代码的Hard编码(要进行强制转换)。
示例代码1:
#include <iostream> #include <string> #include <vector> using namespace std; class Man; class Woman; //行为 class Action { public: virtual void GetManConclusion(Man* concreteElementA) = 0; virtual void GetWomanConclusion(Woman* concreteElementB) = 0; }; //成功 class Success : public Action { public: virtual void GetManConclusion(Man* concreteElementA) { cout<<"男人成功时,背后有个伟大的女人"<<endl; } virtual void GetWomanConclusion(Woman* concreteElementB) { cout<<"女人成功时,背后有个没用的男人"<<endl; } }; //失败 class Failure : public Action { public: virtual void GetManConclusion(Man* concreteElementA) { cout<<"男人失败时,背后有个伟大的女人"<<endl; } virtual void GetWomanConclusion(Woman* concreteElementB) { cout<<"女人失败时,背后有个没用的男人"<<endl; } }; //抽象人类 class Person { public: virtual void Accept(Action* visitor) = 0; }; //男人 class Man : public Person { public: virtual void Accept(Action* visitor) { visitor->GetManConclusion(this); } }; //女人 class Woman : public Person { public: virtual void Accept(Action* visitor) { visitor->GetWomanConclusion(this); } }; //对象结构类 class ObjectStructure { private: vector<Person*> m_personList; public: void Add(Person* p) { m_personList.push_back(p); } void Display(Action* a) { vector<Person*>::iterator p = m_personList.begin(); while (p != m_personList.end()) { (*p)->Accept(a); p ++; } } }; //客户端 int main() { ObjectStructure* os = new ObjectStructure(); os->Add(new Man()); os->Add(new Woman()); Success* success = new Success(); os->Display(success); Failure* fl = new Failure(); os->Display(fl); /*result 男人成功时,背后有个伟大的女人 女人成功时,背后有个没用的男人 男人失败时,背后有个伟大的女人 女人失败时,背后有个没用的男人 */ return 0; } |
示例代码2:
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); } |
main.cpp:
#include "Element.h" #include "Visitor.h" #include <iostream> using namespace std; int main() { Visitor* vis = new ConcreteVisitorA(); Element* elm = new ConcreteElementA(); elm->Accept(vis); /*result I will visit ConcreteElementA ... visiting ConcreteElementA ... */ return 0; } |
访问者模式结构图:
|