欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

命令模式的应用之菜单项命令

程序员文章站 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();
}