第30章 混編模式(1)
阿新 • • 發佈:2018-12-21
30.1 命令鏈模式(命令模式+責任鏈模式)
30.1.1 UNIX下的命令規則(如ls)
(1)命令名為小寫字母
(2)命令名、選項、運算元之間以空格分隔,空格數量不受限制
(3)選項之間可以組合使用,也可以單獨拆分使用
(4)選項以“-”開頭
30.1.2 ls命令詳解(如ls -a -l /usr)
(1)ls:簡單列出一個目錄下的檔案;ls –l:詳細列出目錄下的檔案;ls –a:列出目錄下包含的隱藏檔案,主要是“.”開頭的檔案。
(2)每一個ls命令都有運算元(如usr目錄),預設運算元為當前目錄。
(3)選項不可重複,如ls –l –l –s,解析出的選項應該只有兩個:l選項和s選項
30.1.3 類圖及說明
(1)CommandVo:命令的值物件,它把一個命令解析為命令名、選項、運算元。例如“ls –l /usr”命令分別解析為getCommandName、getparam、getData三個方法的返回值
(2)CommandChain:根據命令選項生成相應的命令處理物件,如“ls –l –a /usr”將生成LS、LS_L、LS_A等3個物件。
(3)FileManager為資源管理器,根據輸入的命令呼叫相應的API來顯示目錄資訊。這裡為簡單起見,只是用字串來簡單模擬。
【程式設計實驗】搬移UNIX的命令
//設計模式混編——命令模式+責任鏈模式 //例項:搬移UNIX的命令 #include <iostream> #include <string> #include <vector> #include <list> #include <map> using namespace std; //*******************************************輔助類*********************************** //命令物件:CommandVo class CommandVo { public: //定義引數名與引數的分隔符號,一般是空格 static const string DIVIDE_FLAG; //定義引數前的符號,UNIX一般是-,如ls -la static const string PREFIX; private: //命令名,如ls,du string commandName; //引數列表(使用map是為了防止引數重複。如ls -l -l -s) map<string,string> paramList; //運算元列表 vector<string> dataList; void init(string& commandStr) { //常規判斷 if(commandStr.length() >0) { //根據分隔符號拆分執行符號 vector<string> complexStr; split(commandStr, DIVIDE_FLAG, complexStr); //第一個引數是執行符號 commandName = complexStr[0]; //把引數放入引數列表中 paramList[""] = ""; for(size_t i=1; i<complexStr.size(); i++) { string str = complexStr[i]; //包括字首符號,認為是引數 trim(str); if(str.find(PREFIX)==0) { str = str.replace(0,1,""); paramList[str] = str; } else { if (str !="") dataList.push_back(str); } } } else { //傳遞的命令錯誤 cout << "命令解析失敗,必須傳遞一個命令才能執行" << endl; } } void split(const string src, const string delim, vector<string>& out) { size_t last = 0; size_t index = src.find_first_of(delim, last); while (index != std::string::npos) { out.push_back(src.substr(last, index-last)); last = index + 1; index = src.find_first_of(delim, last); } if (index-last>0) { out.push_back(src.substr(last, index-last)); } } string& trim(std::basic_string<char>& s) { const string p = " "; s.erase(0, s.find_first_not_of(p)); s.erase(s.find_last_not_of(p) + 1); return s; } public: //通過建構函式傳遞進來命令 CommandVo(string commandStr) { commandName = ""; init(commandStr); } //獲取命令名 string getCommandName(){return commandName;} //獲取引數列表 map<string,string>& getParam() { //為了方便處理空引數 if(paramList.size() == 0) { paramList[""]=""; } return paramList; } //獲取運算元 vector<string>& getData(){return dataList;} //獲得運算元,返回值為string型別 string formatData() { //沒有運算元 if(dataList.size() == 0) { return ""; } else { string ret =""; vector<string>::iterator iter= dataList.begin(); while (iter != dataList.end()) { ret += *iter + " "; ++iter; } return ret; } } }; const string CommandVo::DIVIDE_FLAG = " "; const string CommandVo::PREFIX = "-"; //檔案管理類 class FileManager { public: //ls命令 static string ls(string path) { return "file1\nfile2\nfile3\nfile4\n"; } //ls -l命令 static string ls_l(string path) { string str = "drw-rw-rw root system 1024 2016-7-13 20:42 file1\n"; str += "drw-rw-rw root system 1024 2016-7-13 20:42 file2\n"; str += "drw-rw-rw root system 1024 2016-7-13 20:42 file3\n"; return str; } //ls -a命令 static string ls_a(string path) { string str = ".\n..\nfile1\nfile2\nfile3"; return str; } }; //抽象命令名類(相當於責任鏈的handler角色) class CommandName { private: CommandName* nextOperator; public: string handleMessage(CommandVo& vo) { //處理結果 string result = ""; //判斷是否是自己處理的引數 map<string,string>::iterator iter = vo.getParam().find(getOperateParam()); if(iter != vo.getParam().end() ) { result = echo(vo); if(nextOperator != NULL) { result +="\n" + nextOperator->handleMessage(vo); } } else { result = "命令無法執行"; } return result; } //設定剩餘引數由誰來處理 void setNext(CommandName* cmdName) { nextOperator = cmdName; } virtual ~CommandName(){} protected: //每個處理者都要處理一個字尾引數 virtual string getOperateParam() = 0; //每個處理都必須實現處理任務 virtual string echo(CommandVo& vo) = 0; }; //抽象ls命令 class AbstractLS : public CommandName { public: //預設引數 static const string DEFAULT_PARAM; static const string A_PARAM; static const string L_PARAM; }; const string AbstractLS::DEFAULT_PARAM =""; const string AbstractLS::A_PARAM ="a"; const string AbstractLS::L_PARAM ="l"; //ls命令 class LS : public AbstractLS { protected: //最簡單的ls命令 string echo(CommandVo& vo) { return FileManager::ls(vo.formatData()); } //引數 string getOperateParam() { return AbstractLS::DEFAULT_PARAM; } }; //ls-a命令 class LS_A : public AbstractLS { protected: //最簡單的ls命令 string echo(CommandVo& vo) { return FileManager::ls_a(vo.formatData()); } //引數 string getOperateParam() { return AbstractLS::A_PARAM; } }; //ls-l命令 class LS_L : public AbstractLS { protected: //最簡單的ls命令 string echo(CommandVo& vo) { return FileManager::ls_l(vo.formatData()); } //引數 string getOperateParam() { return AbstractLS::L_PARAM; } }; // class CommandChain { private: list<CommandName*> commandChain; map<string,string>& paramList; public: CommandChain(map<string, string>& paramList):paramList(paramList) { buildChain(); }; //返回連結串列的首節點 CommandName* getFirstNode() { return commandChain.front(); } void buildChain() { //構造連結串列是有順序的:LS-> LS_L -> LS_A map<string, string>::iterator iter = paramList.find(AbstractLS::DEFAULT_PARAM); if(iter !=paramList.end()) { CommandName* cmdLS = new LS(); commandChain.push_back(cmdLS); } iter = paramList.find(AbstractLS::L_PARAM); if(iter !=paramList.end()) { CommandName* cmdLSL = new LS_L(); commandChain.push_back(cmdLSL); } iter = paramList.find(AbstractLS::A_PARAM); if(iter !=paramList.end()) { CommandName* cmdLSA = new LS_A(); commandChain.push_back(cmdLSA); } list<CommandName*>::iterator it = commandChain.begin(); while( it != commandChain.end()) { CommandName* pre = *it; ++it; if (it == commandChain.end()) pre->setNext(NULL); else pre->setNext(*it); } } void deleteChain() { list<CommandName*>::iterator iter = commandChain.begin(); while( iter != commandChain.end()) { delete (*iter); ++iter; } commandChain.clear(); } ~CommandChain() { deleteChain(); } }; //*****************************Command**************************** //抽象命令角色 class Command { protected: CommandName* receiver; //建立連結串列,表頭為命令的接收者,ls和du命令系列做法相同 //這裡只演示ls命令系列組成的連結串列 public: Command(CommandName* receiver) { this->receiver = receiver; } virtual string execute(CommandVo& vo) = 0; virtual ~Command(){} }; //LSCommand class LSCommand :public Command { public: LSCommand(CommandName* commandName):Command(commandName){} string execute(CommandVo& vo) { return receiver->handleMessage(vo); } }; //******************************Invoker*************************** class Invoker { public: string exec(string commandStr) { //定義返回值 string ret =""; //首先解析命令 CommandVo vo(commandStr); CommandChain chain(vo.getParam()); //建立命令 Command* command = new LSCommand(chain.getFirstNode()); ret = command->execute(vo); delete command; return ret; } }; int main() { string cmd ="ls -l -a -l /usr /password"; Invoker invoker; string ret = invoker.exec(cmd); cout <<ret << endl; return 0; }; /*輸出結果: */
30.1.4 小結
(1)責任鏈模式:負責對命令引數進行解析,而且所有的擴充套件都是增加鏈數量和節點,不涉及原有程式碼變更
(2)命令模式:負責命令的分發,把適當的命令分發到指定的鏈上。
(3)該框架還有一個名稱,叫做“命令鏈”(Chain of Command)模式,具體來說就是命令模式作為責任鏈模式的排頭兵,由命令模式分發具體的訊息到責任鏈模式。