1. 程式人生 > 其它 >理解軟體設計模式 - 命令模式

理解軟體設計模式 - 命令模式

技術標籤:設計模式設計模式命令模式

前言

最近學習軟體設計模式看到命令模式,找了好幾篇文章看啊看,都是什麼Receiver啦,Invoker啦,Command啦等等之類的各種新名詞,晦澀難懂,看得實在頭大。。。。
後來轉念一想,臥槽!那麼多新名詞,其實都是我們實實在在用著的東西。

“經典” 的命令模式

為什麼叫“經典”的命令模式呢?因為經典的都讓人搞不懂
命令模式的描述大多都是這樣的:

在軟體開發系統中,“方法的請求者”與“方法的實現者”之間經常存在緊密的耦合關係,這不利於軟體功能的擴充套件與維護。例如,想對方法進行“撤銷、重做、記錄”等處理都很不方便,因此“如何將方法的請求者與實現者解耦?”變得很重要,命令模式就能很好地解決這個問題。

– 引用自 C語言中文網

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

以及uml(引用自 RUNOOB):
引用自RUNOOB

對於我來說看見上面的描述
我的大腦:我拒絕,我不要,我看不懂
我:俺也一樣

後來腦子有了自己的想法

想必大家都瞭解過IOC,如果不瞭解也沒關係,請直接略過。那你一定了解經典的三層架構(你不知道的話我直播吃鍵盤!如果你真的不瞭解我連主機都給吃嘍,如果你確定、一定以及肯定沒了解過,那就當我什麼都沒說)

IOC是怎麼解決耦合的? 就是把耦合交給了Container。
三層是怎麼解決耦合的? 就是不解決。

那麼命令模式就有了用武之地,我們在三層中Service層的類中要使用Dao層中的類一般是這樣的:

//資料訪問層
public class UserDao
{
	public User getUser(){
		return User;
	} 
}
//業務邏輯層
public class UserService 
{
	UserDao userDao = new UserDao();
	
	public User getUser(){
		return userDao.getUser();
	}
}

我們在UserService類裡直接new了一個UserDao出來,可以看出來Service層直接持有了Dao層的物件,Service層與Dao層太緊了。。。額,,,這個緊是耦合得緊。

那麼三層中的UserServcie類就是命令模式中的:Invoker 這個角色
UserDao類就是命令模式中的:Receiver 這個角色
getUser這個操作就可以用來Command物件來表示

所以我們就可以使用命令模式進行UserService(方法的請求者Invoker )與UserDao(方法的實現者Receiver)直接的解耦。
ps:個人認為,這樣描述比用各種新名詞,各種示例又是廚子、又是做飯、又是顧客的各種打比方好理解多了,因為service、dao都是我們所熟悉的東西,不用任何抽象。但是大家還是要知道命令模式中名詞的,比喻只是為了更好的理解

使用命令模式實現三層架構的解耦

我們使用命令模式實現三層架構的解耦
增加 Command 抽象類

public abstract class Command
{
	public object execute();
}

增加GetUserCommand類(Command的實現類)
GetUserCommand 類現在持有了UserDao的引用,它用來執行真正的getUser操作

public class GetUserCommand : Command
{
	UserDao userDao;
	public GetUserCommand()
	{
		userDao = new UserDao();
	}
	public override object execute()
	{
		return userDao.getUser();
	}
}

修改UserService類

//業務邏輯層
public class UserService 
{
	Command getUserCommand = new GetUserCommand();
	
	public User getUser(){
		return getUserCommand.execute() as User;
	}
}

好了,UserService和UserDao的耦合就此斷開,以後如果我們要更換Dao的getUser方法,只需要改動GetUserCommand就行了,與Service層毛關係都沒有(如果Service層有很多地方使用了GetUser方法,不解耦的話就需要改動很多地方)。
以上是理想狀態,只是為了演示命令模式的解耦功能。
UserDao和UserService裡不可能只有這麼一個方法,Command在Service中如何儲存也是個問題(可以用hash表儲存),以及什麼時候去建立Command,如何呼叫對應的Command等等。。。這些不在本文討論範圍。

到這裡可以看到我們把Dao和Service的耦合斷開了,同時我們也看到Service增加了新的依賴:Command相關類,我們把getUser這個操作變成了一個Command物件。

彩蛋

說到解耦,我認為沒有絕對的解耦,只不過是從直接依賴變成了間接依賴。完全解耦??不可能,難道用量子來交流?
以上是個人理解,如果大家有不同意見。我不聽,我不聽,我不聽,拜拜!咱們江湖再見!(歡迎大家評論區留言)