//设计模式之命令(Command)---对象行为型模式( 设计模式学习笔记)
1.意图
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
2.别名 动作(Action),事务(Transaction)
3.适用性
1)抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(callback )函数表达这种参数化机制。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。command 模式是回调机制的一个面向对象的替代品。
2)在不同的时刻指定、排列和执行请求。一个Command 对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。
3)支持取消操作。Command 的Execute 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command 接口必须添加一个UnExecute 操作,该操作取消上一次Execute 调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用UnExecute 和Execute 来实现重数不限的“取消”和“重做”。
4)支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。在Command 接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute 操作重新执行它们。
5) 用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务( transaction )的信息系统中很常见。一个事务封装了对数据的一组变动。Command 模式提供了对事务进行建模的方法。Command 有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。
2)在不同的时刻指定、排列和执行请求。一个Command 对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。
3)支持取消操作。Command 的Execute 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command 接口必须添加一个UnExecute 操作,该操作取消上一次Execute 调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用UnExecute 和Execute 来实现重数不限的“取消”和“重做”。
4)支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。在Command 接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute 操作重新执行它们。
5) 用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务( transaction )的信息系统中很常见。一个事务封装了对数据的一组变动。Command 模式提供了对事务进行建模的方法。Command 有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。
4.结构(如图1)
![](/images/blog_csdn_net/Amoon100/Command1.jpg)
5.参与者
*Command
---声明执行操作的接口。
---声明执行操作的接口。
* ConcreteCommand
---将一个接受者的对象邦定于一个动作。
---调用接受者相应的操作,以实现Execute。
---将一个接受者的对象邦定于一个动作。
---调用接受者相应的操作,以实现Execute。
*Client
---创建一个具体命令对象并设定它的接受者。
---创建一个具体命令对象并设定它的接受者。
*Invoker
---要求该命令执行这个请求。
---要求该命令执行这个请求。
*Receiver
---知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
---知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
6.协作
*Client创建一个ConcreteCommand对象并指定他的Receiver对象。
*某Invoker对象存储该ConcreteCommand对象。
*某Invoker对象存储该ConcreteCommand对象。
*该Invoker通过调用Command 对象的Execute操作来提交一个请求。若该命令是可撤销的,ConcreteCommand就在执行Execute操作之前存储当前状态以用于取消该命令。
*ConcreteCommand对象对调用它的Receiver的一些操作以执行该请求。
下图2展示了这些对象之间的交互。
![](/images/blog_csdn_net/Amoon100/Command2.jpg)
7.实现及代码示例
/************************************************************************
*
*
* 下面的例子为一个一个菜单的打开及复制菜单项的实现
*
*
*************************************************************************/
#include "List.H"
*
*
* 下面的例子为一个一个菜单的打开及复制菜单项的实现
*
*
*************************************************************************/
#include "List.H"
class Document {
public:
Document(const char*);
void Open();
void Paste();
};
public:
Document(const char*);
void Open();
void Paste();
};
class Application {
public:
Application();
void Add(Document*);
};
public:
Application();
void Add(Document*);
};
class Command {
public:
virtual ~Command();
public:
virtual ~Command();
virtual void Execute() = 0;
protected:
Command();
};
protected:
Command();
};
class OpenCommand : public Command {
public:
OpenCommand(Application*);
public:
OpenCommand(Application*);
virtual void Execute();
protected:
virtual const char* AskUser();
private:
Application* _application;
char* _response;
};
protected:
virtual const char* AskUser();
private:
Application* _application;
char* _response;
};
OpenCommand::OpenCommand (Application* a) {
_application = a;
}
_application = a;
}
void OpenCommand::Execute () {
const char* name = AskUser();
const char* name = AskUser();
if (name != 0) {
Document* document = new Document(name);
_application->Add(document);
document->Open();
}
}
Document* document = new Document(name);
_application->Add(document);
document->Open();
}
}
class PasteCommand : public Command {
public:
PasteCommand(Document*);
public:
PasteCommand(Document*);
virtual void Execute();
private:
Document* _document;
};
private:
Document* _document;
};
PasteCommand::PasteCommand (Document* doc) {
_document = doc;
}
_document = doc;
}
void PasteCommand::Execute () {
_document->Paste();
}
_document->Paste();
}
/***********************************************************************
*
*
* 对不需要参数及不能取消的命令,可用C++模板来实现
*
*
***********************************************************************/
template <class Receiver>
class SimpleCommand : public Command {
public:
typedef void (Receiver::* Action)();
*
*
* 对不需要参数及不能取消的命令,可用C++模板来实现
*
*
***********************************************************************/
template <class Receiver>
class SimpleCommand : public Command {
public:
typedef void (Receiver::* Action)();
SimpleCommand(Receiver* r, Action a) :
_receiver(r), _action(a) { }
_receiver(r), _action(a) { }
virtual void Execute();
private:
Action _action;
Receiver* _receiver;
};
private:
Action _action;
Receiver* _receiver;
};
template <class Receiver>
void SimpleCommand<Receiver>::Execute () {
(_receiver->*_action)();
}
void SimpleCommand<Receiver>::Execute () {
(_receiver->*_action)();
}
class MyClass {
public:
void Action();
};
void dummy () {
public:
void Action();
};
void dummy () {
MyClass* receiver = new MyClass;
// ...
Command* aCommand =
new SimpleCommand<MyClass>(receiver, &MyClass::Action);
// ...
aCommand->Execute();
// ...
Command* aCommand =
new SimpleCommand<MyClass>(receiver, &MyClass::Action);
// ...
aCommand->Execute();
}
/********************************************************************
*
*
* 某菜单项需要一系列命令时可如下实现
*
*
*
*********************************************************************/
class MacroCommand : public Command {
public:
MacroCommand();
virtual ~MacroCommand();
virtual void Add(Command*);
virtual void Remove(Command*);
virtual void Remove(Command*);
virtual void Execute();
private:
List<Command*>* _cmds;
};
private:
List<Command*>* _cmds;
};
void MacroCommand::Execute () {
ListIterator<Command*> i(_cmds);
ListIterator<Command*> i(_cmds);
for (i.First(); !i.IsDone(); i.Next()) {
Command* c = i.CurrentItem();
c->Execute();
}
}
Command* c = i.CurrentItem();
c->Execute();
}
}
void MacroCommand::Add (Command* c) {
_cmds->Append(c);
}
_cmds->Append(c);
}
void MacroCommand::Remove (Command* c) {
_cmds->Remove(c);
}
_cmds->Remove(c);
}
8.与其他模式的联系
1)组合模式( Composite) 可被用来实现宏命令.
2)备忘录模式( Memento) 可用来保持某个状态,命令用这一状态来取消它的效果.