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)模式,具体来说就是命令模式作为责任链模式的排头兵,由命令模式分发具体的消息到责任链模式。