1. 程式人生 > >《設計模式》學習筆記——命令模式

《設計模式》學習筆記——命令模式

        命令模式(Command Pattern)是一種資料驅動的設計模式,它屬於行為型模式。 請求以命令的形式包裹在物件中,並傳給呼叫物件。呼叫物件尋找可以處理該命令的合適的物件,並把該命令傳給相應的物件,該物件執行命令。

意圖:     將一個請求封裝成一個物件,從而使您可以用不同的請求對客戶進行引數化。主要解決:     在軟體系統中,行為請求者與行為實現者通常是一種緊耦合的關係.     但某些場合,比如需要對行為進行記錄、撤銷或重做、事務等處理時,這種無法抵禦變化的緊耦合的設計就不太合適。何時使用:     在某些場合,比如要對行為進行"記錄、撤銷/重做、事務"等處理,這種無法抵禦變化的緊耦合是不合適的。     在這種情況下,如何將"行為請求者"與"行為實現者"解耦?將一組行為抽象為物件,可以實現二者之間的鬆耦合。如何解決:

    通過呼叫者呼叫接受者執行命令,順序:呼叫者→接受者→命令。關鍵程式碼:     定義三個角色:     1、received 真正的命令執行物件      2、Command      3、invoker 使用命令物件的入口應用例項:     struts 1 中的 action 核心控制器 ActionServlet 只有一個.     相當於 Invoker,而模型層的類會隨著不同的應用有不同的模型類,相當於具體的 Command。優點:      1、降低了系統耦合度。      2、新的命令可以很容易新增到系統中去。缺點:     使用命令模式可能會導致某些系統有過多的具體命令類。使用場景:
    認為是命令的地方都可以使用命令模式,比如:                                              1、GUI 中每一個按鈕都是一條命令。                                             2、模擬 CMD。注意事項:     系統需要支援命令的撤銷(Undo)操作和恢復(Redo)操作,也可以考慮使用命令模式,見命令模式的擴充套件。

CommandPattern.h

#pragma once
#include<iostream>
#include<string>
#include<list>

class Docter
{
public:
	void treat_eye()
	{
		std::cout << "Docter treat_eye()" << std::endl;
	}
	void treat_nose()
	{
		std::cout << "Docter treat_nose()" << std::endl;
	}

private:
protected:
};

// 抽象命令類
class CommandPattern
{
public:
	CommandPattern() {};
	~CommandPattern() {};
	virtual void docterTreat() = 0;			// 抽象介面
};

// 命令類
class CommandDocterTreatEye:public CommandPattern
{
public:
	CommandDocterTreatEye(Docter* docter):m_docter(docter){};	// 傳入引數,也叫注入引數
	~CommandDocterTreatEye() {};
	virtual void docterTreat()									// 抽象介面實現
	{
		docterTreatEye();										// 實際呼叫
	}		
private:
	Docter * m_docter;			// 更好的方法是傳入Docter類的純虛基類做為一層介面,然後利用多型思想解耦和
	void docterTreatEye() { m_docter->treat_eye(); }			
protected:
};

// 命令類
class CommandDocterTreatNose :public CommandPattern
{
public:
	CommandDocterTreatNose(Docter* docter) :m_docter(docter) {};	// 傳入引數,也叫注入引數
	~CommandDocterTreatNose() {};

	virtual void docterTreat()									// 抽象介面實現
	{
		docterTreatNose();										// 實際呼叫
	}	
private:
	Docter * m_docter;			// 更好的方法是傳入Docter類的純虛基類做為一層介面,然後利用多型思想解耦和
	void docterTreatNose() { m_docter->treat_nose(); }			// 實際呼叫
protected:
};

// 護士類,命令的發起者
class BeautyNurse
{
public:
	BeautyNurse(CommandPattern * commandpattern): m_commandpattern(commandpattern){}
	~BeautyNurse() {}

	void SubmitteCase()			// 案例提交,下達命令
	{
		m_commandpattern->docterTreat();		// 讓醫生治療
	}
private:
	CommandPattern * m_commandpattern;			// 能夠採集命令
protected:
};

// 護士長類,命令的批量發起者
class AdvHeadNurse
{
public:
	AdvHeadNurse()
	{
		m_commandPatternList.clear();			// 初始狀態清空列表
	}
	~AdvHeadNurse() {}

	void setCommend(CommandPattern * command)
	{
		m_commandPatternList.push_back(command);	// 向列表新增命令
	}
	void SubmitteCase()			// 案例提交,下達命令
	{
		for (auto it = m_commandPatternList.begin(); it != m_commandPatternList.end(); it++)
			(*it)->docterTreat();

	}
private:
	std::list<CommandPattern *> m_commandPatternList;// 能夠採集一批命令
protected:
};



CommandPattern.cpp

#include "CommandPattern.h"


mainTest.cpp


#include<iostream>
#include<string>
#include "CommandPattern.h"

int mainTest1(void)
{
	// 建立一個醫生物件
	Docter* docter = new Docter;
	// 建立一個命令物件
	CommandPattern* commandPattern = new CommandDocterTreatNose(docter);	// 通過構造注入一個物件
	// 執行
	commandPattern->docterTreat();
	// 執行結束,刪除物件
	delete commandPattern;

	// 建立一個新命令物件
	commandPattern = new CommandDocterTreatEye(docter);		// 通過構造注入另一個物件
	// 執行
	commandPattern->docterTreat();
	// 執行結束,刪除物件
	delete commandPattern;
	// 刪除物件
	delete docter;
	return 0;
}

int mainTest2()
{
	

	// 建立一個醫生物件
	Docter* docter = new Docter;
	// 建立一個命令物件
	//CommandPattern* commandPattern = new CommandDocterTreatNose(docter);	// 通過構造注入一個物件		
	CommandPattern* commandPattern = new CommandDocterTreatEye(docter);		// 通過構造注入一個物件		
	BeautyNurse* beautynurse = new BeautyNurse(commandPattern);				// 建立一個護士物件,命令傳達者
	beautynurse->SubmitteCase();											// 護士提交案例,傳達命令

	// 執行結束,刪除物件
	delete beautynurse;
	// 執行結束,刪除物件
	delete commandPattern;
	// 刪除物件
	delete docter;


	system("pause");
	return 0;
}

int main()
{
	//mainTest1();
	//mainTest2();

	// 建立一個醫生物件
	Docter* docter = new Docter;
	// 建立一個命令物件
	CommandPattern* commandPattern1 = new CommandDocterTreatNose(docter);	// 通過構造注入一個物件		
	CommandPattern* commandPattern2 = new CommandDocterTreatEye(docter);	// 通過構造注入一個物件	
	// 建立一個護士長物件
	AdvHeadNurse* advHeadNurse = new AdvHeadNurse();						// 建立一個護士物件,命令傳達者
	// 插入命令									插入命令可以修改擴充套件新增對可變引數的支援,能夠更加友好
	advHeadNurse->setCommend(commandPattern1);
	advHeadNurse->setCommend(commandPattern2);
	// 批量傳達命令
	advHeadNurse->SubmitteCase();											// 護士提交案例,傳達命令

	// 執行結束,刪除物件						
	delete advHeadNurse;
	// 執行結束,刪除物件
	delete commandPattern2;
	// 執行結束,刪除物件
	delete commandPattern1;
	// 刪除物件
	delete docter;


	system("pause");
	return 0;
}