現在幾乎每個軟體都有Undo和Redo功能,要想實現這個功能就要用到COMMAND模式。所有的操作都應該從類似如下的抽象類別CCommand繼承:
class CCommand{public: virtual ~CCommand(); virtual void Do() = 0; virtual void Undo() = 0;};
這樣就可以在操作的時候,先建立一個該操作的對象,然後先調該對象的Do方法,再將該對象壓入一個undo棧中。如果要undo操作,則從該棧頂彈出一個操作的對象,調用它的Undo方法,並把該對象壓入另外一個redo棧中。如果要redo操作,就從redo棧頂彈出一個操作的對象,調用它的Do方法,並把該對象重新壓回undo棧中。下面就是一個簡單的實現:
class CCommandList{public: ~CCommandList(); // SINGLETON模式用到的友元函數 friend CCommandList& CreateCommandList(); // 添加命令 void Add(CCommand* pCmd); // undo命令 void Undo(); // redo命令 void Redo();private: CCommandList(); CCommandList(const CCommandList&); // 用STL中的vector來實現棧的功能 vector<CCommand*> m_vUndo; vector<CCommand*> m_vRedo;};// 建立唯一的執行個體CCommandList& CreateCommandList(){ static CCommandList Instance; return Instance;}CCommandList::CCommandList(){}CCommandList::CCommandList(const CCommandList&){}CCommandList::~CCommandList(){ while(!m_vUndo.empty()) { CCommand* pCmd = (CCommand*)m_vUndo.back(); m_vUndo.pop_back(); delete pCmd; } while(!m_vRedo.empty()) { CCommand *pCmd = (CCommand*)m_vRedo.back(); m_vRedo.pop_back(); delete pCmd; }}void CCommandList::Add(CCommand *pCmd){ m_vUndo.push_back(pCmd);}void CCommandList::Undo(){ if(!m_vUndo.empty()) { CCommand *pCmd = (CCommand*)m_vUndo.back(); pCmd->Undo(); m_vUndo.pop_back(); m_vRedo.push_back(pCmd); }}void CCommandList::Redo(){ if(!m_vRedo.empty()) { CCommand *pCmd = (CCommand*)m_vRedo.back(); pCmd->Do(); m_vRedo.pop_back(); m_vUndo.push_back(pCmd); }}
上面的類CCommandList用起來很簡單。先調用CreateCommandList函數建立一個唯一的CCommandList對象;對每個操作,都要先建立一個該操作的命令,調用它的Do方法,然後調用類CCommandList的Add方法將該命令添加入棧;然後就可以用類CCommandList來實現命令的undo和redo了。
在上面類CCommandList的實現中,我使用了SINGLETON模式,那是因為在一個應用程式中應該只有一個類CCommandList的對象。對於SINGLETON模式,可以參考我的另一篇文章《重讀《設計模式》之學習筆記(三)--SINGLETON模式的疑惑》。
轉自:
http://blog.csdn.net/starlee/article/details/984127
另附:
.NET設計模式(17):命令模式(Command Pattern)