命令模式的应用之菜单项命令
程序员文章站
2022-05-24 23:53:40
...
思考命令模式
①命令模式的本质:封装请求。这是也命令模式的关键。把请求封装成对象,也就是命令对象,并定义了统一的执行操作的接口。这个命令对象可以被存储、转发、记录、处理、撤销等。整个命令模式都是围绕这个对象进行的。
②命令模式的动机:在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合——比如需要对行为进行“记录、撤销/重做”、事务”等处理,这种无法抵御变化的紧耦合是不合适的,命令模式的动机就是将一组行为抽象为对象,可以实现二者之间的构耦合。
③命令模式的组装和调用
命令的组装者:用它维护命令的“虚”实现和真实实现之间的关系。(即下图中的Client,但将之定义成组装者更合适。真正的Client是通过Invoker来触发命令的)
④命令的接收者:可以是任意的类,对它没有特殊要求。一个接收者可以处理多个命令,接收者提供的方法个数、名称、功能和命令对象中的可以不一样,只要能够通过调用接收者的方法来实现命令对应的功能就可以了。
⑤智能命令:在标准的命令模式中,命令的实现类是没有真正实现命令要求的功能的,真正执行命令的功能的是接收者。如果命令对象自己实现了命令要求的功能,而不再需要调用接收者,那这种情况称为智能命令。也有半智能的命令,即命令对象实现一部分,其他的还是需要调用接收者来完成,也就是说命令的功能由命令对象和接收者共同来完成。
【编程实验】菜单项命令
//声明文件
//******************************************************************************************
//行为型模式:命令模式
//场景:菜单项命令
/*
要求:某软件公司欲开发一个基于Windows平台的公告板系统。系统提供一个主菜单(Menu),
在主菜单中包含了一些菜单项(MenuItem),可以通过Menu类的addMenuItem()方法增加
菜单项。菜单项的主要方法是click(),每一个菜单项包含一个抽象命令类,具体命令
类包括OpenCommand(打开命令),CreateCommand(新建命令),EditCommand(编辑命令)
等,命令类具有一个execute()方法,用于调用公告板系统界面类(Board)的open()、
create()、edit()等方法。试使用命令模式设计该系统,使得MenuItem类与Board类
的耦合度降低,绘制类图并编程模拟实现。
*/
#include <iostream>
#include <string>
#include <map>
using namespace std;
//******************************Receiver********************
//Board(公告板)
class CBoard{
public:
void Open();
void Create();
void Edit();
};
//****************************Command************************
//Command命令接口
class CMenuCmd{
public:
virtual void Execute() = 0;
};
//CreateCommand(“新建”)
class CCreateCmd : public CMenuCmd{
private:
CBoard* pBoard;
public:
CCreateCmd(CBoard* board);
void Execute();
};
//OpenCommand(“打开”)
class COpenCmd : public CMenuCmd{
private:
CBoard* pBoard;
public:
COpenCmd(CBoard* board);
void Execute();
};
//EditCommand(“编辑”)
class CEditCmd : public CMenuCmd{
private:
CBoard* pBoard;
public:
CEditCmd(CBoard* board);
void Execute();
};
//*****************************Invoker****************************
//MenuItem(菜单项)
class CMenuItem{
private:
string strItem;
CMenuCmd* pCmd;
public:
CMenuItem(string item, CMenuCmd* cmd);
void SetItem(string item);
string GetItem();
void SetCmd(CMenuCmd* cmd);
CMenuCmd* GetCmd();
//单击事件
//因菜单项(命令发送者)与具体的消息接收者(如board)的解耦
//因此,对于不同的菜单项,这里都可以像如下那样处理。(简洁、灵活!)
void Clicked();
};
//Menu(菜单)
class CMenu{
private:
map<string, CMenuItem*> mpItem;
public:
~CMenu();
void AddMenuItem(CMenuItem* item);
CMenuItem* GetMenuItem(string item);
void RemoveAll();
};
//实现文件
//*******************************************************************************************
void CBoard::Open(){cout << "打开!" << endl;}
void CBoard::Create(){cout << "新建!" << endl;}
void CBoard::Edit(){cout << "编辑!" << endl;}
//****************************Command************************
//Command命令接口
//CreateCommand(“新建”)
CCreateCmd::CCreateCmd(CBoard* board){pBoard = board;}
void CCreateCmd::Execute(){pBoard->Create();}
//OpenCommand(“打开”)
COpenCmd::COpenCmd(CBoard* board){pBoard = board;}
void COpenCmd::Execute(){pBoard->Open();}
//EditCommand(“编辑”)
CEditCmd::CEditCmd(CBoard* board){pBoard = board;}
void CEditCmd::Execute(){pBoard->Edit();}
//*****************************Invoker****************************
//MenuItem(菜单项)
CMenuItem::CMenuItem(string item, CMenuCmd* cmd){strItem = item; pCmd = cmd;}
void CMenuItem::SetItem(string item){strItem = item;}
string CMenuItem::GetItem(){return strItem;}
void CMenuItem::SetCmd(CMenuCmd* cmd){pCmd = cmd;}
CMenuCmd* CMenuItem::GetCmd(){return pCmd;}
//单击事件
//因菜单项(命令发送者)与具体的消息接收者(如board)的解耦
//因此,对于不同的菜单项,这里都可以像如下那样处理。(简洁、灵活!)
void CMenuItem::Clicked(){pCmd->Execute();}
//Menu(菜单)
CMenu::~CMenu(){RemoveAll();}
void CMenu::AddMenuItem(CMenuItem* item){mpItem[item->GetItem()] = item;
}
CMenuItem* CMenu::GetMenuItem(string item){return mpItem[item];}
void CMenu::RemoveAll(){
cout << "Before deleting... size : " << mpItem.size() << endl;
for(map<string, CMenuItem*>::iterator it = mpItem.begin(); it != mpItem.end(); ){
cout << (*it).first << endl;
CMenuItem* pItem = (*it).second; delete pItem;
it = mpItem.erase(it);
}
cout << "After deleted... size : " << mpItem.size() << endl;
}
//测试客户端
void main()
{
CBoard oBoard; //创建公告板(命令接收者)
CCreateCmd oCreateCmd(&oBoard);
COpenCmd oOpenCmd(&oBoard);
CEditCmd oEditCmd(&oBoard);
//创建主菜单及菜单项
CMenu oMenu;
CMenuItem* pCreateItem = new CMenuItem("Create", &oCreateCmd);
CMenuItem* pOpenItem = new CMenuItem("Open", &oOpenCmd);
CMenuItem* pEditItem = new CMenuItem("Edit", &oEditCmd);
oMenu.AddMenuItem(pCreateItem);
oMenu.AddMenuItem(pOpenItem);
oMenu.AddMenuItem(pEditItem);
//测试
//单击“创建公告板”菜单项
oMenu.GetMenuItem("Create")->Clicked();
//单击“打开公告板”菜单项
oMenu.GetMenuItem("Open")->Clicked();
//单击“编辑公告板”菜单项
oMenu.GetMenuItem("Edit")->Clicked();
}
上一篇: 命令行计算器