在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如需要对行为进行“记录、撤销/重做(undo/redo)、事务”等处理,这种无法抵御变化的紧耦合是不合适的。Command设计模式就是在这种情况下,将“行为请求者”与“行为实现者”解耦,将一组行为抽象为对象,以实现二者之间的松耦合。
“Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.” – GoF
将一个请求封装为一个对象,从而可用不同的请求(一个被封装成了对象的请求)对客户程序(即调用者)进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
实例分析,实际工作中,我们遇到了很多文档,都支持回退/前进的功能,它们快捷键也是惊人的相似Ctrl+z与Ctrl+y。下面将用一段代码来实现其操作,其原理就是命令模式。
#include <iostream>
#include <stack>
class Receiver
{
private:
std::string str;
public:
std::string get_str(){ return str; }
void set_str(const std::string& s){ str=s; }
void append(std::string astr){ str.append(astr); }
void show(){ std::cout<<str<<std::endl; }
};
class Command
{
public:
virtual void execute()=0;
Command(Receiver *re,const std::string& p)
:r(re),par(p)
{}
virtual ~Command(){}
protected:
Receiver * r;
std::string par;
};
class UndoCommand:public Command
{
public:
UndoCommand(Receiver *re,const std::string& p)
:Command(re,p)
{}
virtual void undo()=0;
virtual void redo()=0;
virtual ~UndoCommand(){}
};
class ConcreteCommand:public UndoCommand
{
public:
ConcreteCommand(Receiver *re,const std::string& p)
:UndoCommand(re,p)
{}
void execute()
{
preStr=r->get_str();
r->append(par);
curStr=r->get_str();
}
void undo()
{
r->set_str(preStr);
}
void redo()
{
r->set_str(curStr);
}
private:
std::string preStr;
std::string curStr;
};
class ConcreteManager
{
private:
std::stack<Command*> exeComStack;
std::stack<Command*> undoComStack;
public:
void executeCommand(Command* cmd);
void undoCommand();
void redoCommand();
~ConcreteManager();
};
ConcreteManager::~ConcreteManager()
{
while(exeComStack.size()>0)
{
delete exeComStack.top();
exeComStack.pop();
}
while(undoComStack.size()>0)
{
delete undoComStack.top();
undoComStack.pop();
}
}
void ConcreteManager::executeCommand(Command* cmd)
{
cmd->execute();
exeComStack.push(cmd);
}
void ConcreteManager::undoCommand()
{
if(exeComStack.size()>0)
{
UndoCommand *cmd =dynamic_cast<UndoCommand*>(exeComStack.top());
exeComStack.pop();
cmd->undo();
undoComStack.push(cmd);
}
}
void ConcreteManager::redoCommand()
{
if(undoComStack.size()>0)
{
UndoCommand * cmd=dynamic_cast<UndoCommand*>(undoComStack.top());
undoComStack.pop();
cmd->redo();
exeComStack.push(cmd);
}
}
int main(int argc,char** argv)
{
ConcreteManager *co=new ConcreteManager;
Receiver* re=new Receiver;
Command* cm1=new ConcreteCommand(re,"hu");
Command* cm2=new ConcreteCommand(re,"cs");
Command* cm3=new ConcreteCommand(re,"dn");
Command* cm4=new ConcreteCommand(re,"!!");
co->executeCommand(cm1);
co->executeCommand(cm2);
co->executeCommand(cm3);
co->executeCommand(cm4);
re->show();
co->undoCommand();
co->undoCommand();
co->undoCommand();
re->show();
co->redoCommand();
co->redoCommand();
co->redoCommand();
co->redoCommand();
re->show();
delete re;
delete co;
return 0;
}
singleton pattern--单件模式factory mothed pattern--工厂方法模式abstract factory pattern--抽象工厂模式builder pattern--建造者模式prototype pattern--原型模式adapter pattern--适配器模式bridge pattern -- 桥接模式composite pattern -- 组合模式decorator pattern -- 装饰模式decorator pattern -- 享元模式decorator pattern -- 代理模式decorator pattern -- 责任链模式decorator pattern -- 命令模式