在軟件構建過程中,“行為請求者”與“行為實現者”通常呈現一種“緊耦合”。但在某些場合,比如需要對行為進行“記錄、撤銷/重做(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
將一個請求封裝為一個對象,從而可用不同的請求(一個被封裝成了對象的請求)對客戶程序(即調用者)進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作。www.2cto.com
實例分析,實際工作中,我們遇到了很多文檔,都支持回退/前進的功能,它們快捷鍵也是驚人的相似Ctrl+z與Ctrl+y。下面將用一段代碼來實現其操作,其原理就是命令模式。
[cpp] www.2cto.com
#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 -- 命令模式