概述:
命令模式(Command Pattern)是一種數據驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在對象中,並傳給調用對象。調用對象尋找可以處理該命令的合適的對象,並把該命令傳給相應的對象,該對象執行命令。
應用場景:
日誌記錄,撤銷操作,隊列請求
優/缺點:
優點:
1、降低了系統耦合度。
2、新的命令可以很容易添加到系統中去
缺點:
使用命令模式可能會導致某些系統有過多的具體命令類。
前提引入:
最近大家都在搞智能家居,構建自己的生態,阿呆的老闆身為中國五十萬強公司的老闆,豈能沒有嗅到這其中的商機呢?於是讓連忙阿呆停下手中的工作,畢竟作為公司唯一的技術人員,阿呆還是很受重用的。
老闆;阿呆啊,你來公司已經有兩年了吧,你摸著自己的良心給我說,我待你如何?
阿呆:那沒得說,對我簡直不能再好了,有好幾次我都覺得好像我是您失散多年的父,不對,兒子一樣。(冷汗...不會要開除我吧)
老闆:你能這樣說我就放心了,是這樣,最近我看新聞說這個智能家居是一個新的潮流,常常跟你講,我們要懂得抓住未來,你要是有我一半的智慧,也早就成為公司的二把手了。是這樣的,我們公司三個員工,在管理上佔據了我相當大的精力了,如果再來一家公司要我管理的話,那是真的兩個腦袋也管不過來啊。所以我打算成立一個做智能家居的新公司,我看那個什麼公司來著,小麥?就做的挺好的嘛。
阿呆:是小米。
老闆:對對,小米,考慮到我們自身的情況確實和小米差點,所以新公司小木集團,我打算派你去管理。
阿呆:真的嗎(感動中...雖然老闆平時喜歡拖欠工資,把人當苦力,天天九九六,加班不給錢,.....但沒想到老闆組建分公司第一個想到的就是自己,放心吧老闆,我阿呆追隨你到天涯海角,你跑路我跟你跑!),那研發費用,還要招新員工的錢?
老闆:等你盈利之前,就先從你工資里扣吧。
阿呆:吐血
好尬.....
阿呆看著自己那點工資,心想啥也做不出來啊,別說做家居了,買家居的錢都沒有。那做什麼呢,做電視吧,算了吧,做個遙控器還差不多? !!! 就做遙控器!
小木牌智能遙控器,一鍵配對,按鍵功能隨心搭配,一個遙控器在手,去哪看電視都不愁!
那麼問題來了,既然要做到遙控器每個按鈕的功能可以更換,那勢必不能按照傳統的方法來開發了,有過之前的教訓,阿呆已經明白,寫一個類把所有功能寫死是萬萬不能的,那應該怎麼做呢,這時候就該我們的命令模式派上用場了,當然,這裡直接舉例代碼說明是不太容易幫助我們剛學習設計模式的小夥伴們理解的,大家不妨這樣想:
在一個軍隊中,將軍突然渴了,於是想到張三是負責接水的,就讓張三送水來喝,餓了,想起來廚師是李四,於是就讓李四去做飯送來吃,當然,記住兩個人的名字對於將軍來說並非難事,那要是將軍是個事兒多的人呢,可能就要記住成千上百個人的名字和他們對應的職務了,這對於將軍來說肯定不能把精力花在記名字這件事情上,否則就會造成打仗打不好,這個時候我們引入管家這個概念,因為管家不需要打仗,所以管家有足夠多的精力去記名字,名字過多時,我們也可以設立多個管家來解決,所有當將軍餓的時候,只需要說一句"我餓了,送飯來"就行了,管家聽到之後,於是把李四叫過來把飯做好,然後給將軍享用。在這個例子中,
將軍是不知道李四是負責做飯的,李四也不知道將軍的存在,所以即使換了別的人做將軍,或者換了別的人做飯,只要管家還在,對於整個系統就是沒有影響的,所以降低了將軍和李四之間的耦合。因為有了管家這個角色的存在,我們甚至可以做到,李四把飯做好的時候,管家記錄李四做的什麼飯(應用場景中的日誌記錄),飯做的不好吃讓李四回去重新做(撤銷,更改等操作),同理,命令模式也是這樣,調用者只負責發送命令,而不需要關心誰來具體執行業務邏輯。看代碼:
代碼實戰
Receiver接口:接收者接口
/***
*
* @author 韓數
* 定義業務實現的行為。
*
*/
public interface Receiver {
//業務邏輯接口,接收者知道業務邏輯的具體實現方法
public void action();
}
UpReceiverImpl類:接收者遙控器打開功能實現
/***
*
* @author 韓數
* 業務邏輯的具體實現,在這裡主要是指遙控器的開操作。
*
*/
public class UpReceiverImpl implements Receiver{
@Override
public void action() {
// TODO Auto-generated method stub
System.out.println("打開電視!");
}
}
Command:命令接口,定義命令的行為:
/***
*
* @author 韓數
* 命令接口,定義命令的行為,比如撤銷,更改等操作都適合在這裡定義。
*
*/
public interface Command {
/***
* 命令執行的方法
*/
public void execute();
}
ConcreteCommand:命令的具體實現類:
/****
*
* @author 韓數
* 具體的命令實現類,在這裡完成Reciver和Command之間的綁定。
*
*/
public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
//實際的業務邏輯是委託給Reciver對象來執行的。
@Override
public void execute() {
// TODO Auto-generated method stub
receiver.action();
}
}
Invoker:調用者
/***
*
* @author 韓數
* 調用者,調用者不知道是具體的服務提供方是誰,只知道對應的Command命令,通過命令中封裝的具體服務實例,從而實現了代碼間的解耦合。
*
*/
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void action() {
command.execute();
}
}
測試:
/***
*
* @author 客戶端
* 模擬一個命令模式執行的流程
*
*/
public class Client {
public static void main(String[] args) {
Receiver receiver = new UpReceiverImpl();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.action();
}
}
OUTPUT:
打開電視!
總結:
以上就是命令模式的一個簡單的實現了,至於如何實現操作的撤銷,更改,記錄等操作,我這裡更多的是想小夥伴們自己去動腦實現,技術的養成並非一朝一夕,要經過自己的思考才能得到真正的理解,希望對你們有用吧~
閱讀更多 Java架構Monster 的文章