設計模式之八命令模式

生活場景: 普通用戶電腦開機問題,客戶端發出命令或請求,不關心真正的接收者是誰,也不關心具體如何實現,而且同一個請求的動作可以有不同的請求內容,當然具體的處理功能也不一樣。

同理: 老闆(Boss)給項目經理(Leader)下達任務,項目經理會根據實際情況給每個員工派發任務,待員工把任務完成後,再由項目經理向老闆彙報結果。

概念

將一個請求封裝成一個對象,從而使你可用不同的請求對客戶進行參數化,對請求排隊或記錄請求日誌,以及支持可撤銷的操作。將”發出請求的對象”和”接收與執行這些請求的對象”分隔開來。

參與者

序號 參與者 說明
1 Command 聲明執行操作的接口
2 ConcreteCommand 將一個接收者對象綁定於一個動作, 調用接收者相應的操作,以實現Execute
3 Client 創建一個具體命令對象並設定它的接收者。
4 Invoker 要求該命令執行這個請求。
5 Receiver 知道如何實現與執行一個請求相關的操作。任何類都可能作爲一個接收者。

舉個栗子:
Client: 看電視的人
Invoker: 遙控器
Command: 電信號
ConcreteCommand: 具體命令,遙控器上的按鍵對應的不同的電信號
Receiver: 電視機

相關的類圖

在這裏插入圖片描述

案例一

模擬電腦開機的案例

package com.hanker.dao.impl;
//主板接口--抽象Receiver
interface MainBoardApi{
	public void open();//開機功能
}
//技嘉主板--具體接收者Receiver
class GigaMainBoard implements MainBoardApi{
	//真正的開機命令的實現
	public void open() {
		System.out.println("技嘉主板現在正在開機,請稍候...");
		System.out.println("接通電源...");
		System.out.println("設備檢查...");
		System.out.println("裝載系統...");
		System.out.println("機器已經正常打開,請操作...");
	}
}
//微星主板--具體接收者Receiver
class MsiMainBoard implements MainBoardApi{
	//真正的開機命令的實現
	public void open() {
		System.out.println("微星主板現在正在開機,請稍候...");
		System.out.println("接通電源...");
		System.out.println("設備檢查...");
		System.out.println("裝載系統...");
		System.out.println("機器已經正常打開,請操作...");
	}
}
//命令接口
interface Command{
	public void execute(); //執行命令
}
//開機命令--具體Command
class OpenCommand implements Command{
	private MainBoardApi mainBoard;//持有真正的實現命令的接受者——主板對象
	//構造方法傳入主板對象
	public  OpenCommand(MainBoardApi mainBoardApi) {
		this.mainBoard = mainBoardApi;
	}
	@Override
	public void execute() {
		//對於命令對象,根本不知道如何開機,會轉調用主板對象
		//讓主板對象去完成開機的功能
		this.mainBoard.open();
	}
}
//機箱對象--調用者Invoker
class Box{
	private Command openCommand;//開機命令對象
	//設置開機命令對象
	public void setCommand(Command command) {
		this.openCommand = command;
	}
	//提供給客戶使用,接收並響應用戶請求,相當於按鈕被按下觸發的方法
	public void openButtonPressed() {
		openCommand.execute();
	}
}
public class CommandPatternTest2 {
	//client
	public static void main(String[] args) {
		//1.把命令和真正的實現組合起來,相當於在組裝機器
		//把機箱上按鈕的連接線插接到主板上
		MainBoardApi mainBoard = new GigaMainBoard();
		Command openCommand = new OpenCommand(mainBoard);
		//2.爲機箱上的按鈕設置相應的命令,讓按鈕知道該幹什麼
		Box box = new Box();
		box.setCommand(openCommand);
		//3.模擬按下機箱上的按鈕
		box.openButtonPressed();
	}
}

在這裏插入圖片描述

參數化配置

所謂命令模式的參數化配置,指的是:可以用不同的命令對象,去參數化配置客戶的請求。
下面增加一個命令重啓命令,實現參數化配置。在原來的代碼上增加方法:

package com.kongfanyu.springcloud.config;
//主板接口
interface MainBoardApi{
	public void open();//開機功能
	public void reset();//重啓功能
}
//技嘉主板
class GigaMainBoard implements MainBoardApi{
	//真正的開機命令的實現
	public void open() {
		System.out.println("技嘉主板現在正在開機,請稍候...");
		System.out.println("接通電源...");
		System.out.println("設備檢查...");
		System.out.println("裝載系統...");
		System.out.println("機器已經正常打開,請操作...");
	}

    //真正重啓命令的實現
    @Override
    public void reset() {
        System.out.println("技嘉主板現在正在重新啓動機器,請等候..");
        System.out.println("機器已經正常打開,請操作");
    }
}
//微星主板
class MsiMainBoard implements MainBoardApi{
	//真正的開機命令的實現
	public void open() {
		System.out.println("微星主板現在正在開機,請稍候...");
		System.out.println("接通電源...");
		System.out.println("設備檢查...");
		System.out.println("裝載系統...");
		System.out.println("機器已經正常打開,請操作...");
	}
    //真正重啓命令的實現
    @Override
    public void reset() {
        System.out.println("微星主板現在正在重新啓動機器,請等候..");
        System.out.println("機器已經正常打開,請操作");
    }
}
//命令接口
interface Command{
	public void execute(); //執行命令
}
//開機命令
class OpenCommand implements Command{
	private MainBoardApi mainBoard;//持有真正的實現命令的接受者——主板對象
	//構造方法傳入主板對象
	public  OpenCommand(MainBoardApi mainBoardApi) {
		this.mainBoard = mainBoardApi;
	}
	@Override
	public void execute() {
		//對於命令對象,根本不知道如何開機,會轉調用主板對象
		//讓主板對象去完成開機的功能
		this.mainBoard.open();
	}
}
//重啓命令
class ResetCommand implements Command{
    private MainBoardApi mainBoard;//持有真正的實現命令的接受者——主板對象
    //構造方法傳入主板對象
    public  ResetCommand(MainBoardApi mainBoardApi) {
        this.mainBoard = mainBoardApi;
    }
    @Override
    public void execute() {
        //對於命令對象,根本不知道如何重啓機器,會轉調用主板對象
        //讓主板去完成重啓機器的功能
        this.mainBoard.reset();
    }
}
//機箱對象
class Box{
	private Command openCommand;//開機命令對象
    private Command resetCommand;//重啓機器命令對象
	//設置開機命令對象
	public void setCommand(Command command) {
		this.openCommand = command;
	}
	//設置重啓命令對象
    public void setResetCommand(Command command){
	    this.resetCommand = command;
    }
	//提供給客戶使用,接收並響應用戶請求,相當於按鈕被按下觸發的方法
	public void openButtonPressed() {
		openCommand.execute();
	}
	//提供給用戶使用,接收並響應用戶請求,相當於重啓按鈕被按下觸發的方法
    public void resetButtonPressed(){
        //按下按鈕,執行命令
        this.resetCommand.execute();;
    }
}
public class CommandPatternTest2 {

	public static void main(String[] args) {
		//1.把命令和真正的實現組合起來,相當於在組裝機器
		//把機箱上按鈕的連接線插接到主板上
		MainBoardApi mainBoard = new GigaMainBoard();
		//創建開機命令
		Command openCommand = new OpenCommand(mainBoard);
		Command resetCommand = new ResetCommand(mainBoard);
		//2.爲機箱上的按鈕設置相應的命令,讓按鈕知道該幹什麼
		Box box = new Box();
		box.setCommand(openCommand);
		box.setResetCommand(resetCommand);
		//3.模擬按下機箱上的按鈕
        System.out.println("正確配置下=======================>");
        System.out.println(">>>按下開機按鈕:>>>");
        box.openButtonPressed();
        System.out.println(">>>按下重啓按鈕:>>>");
        box.resetButtonPressed();
	}
}

執行結果:

正確配置下=======================>
>>>按下開機按鈕:>>>
技嘉主板現在正在開機,請稍候...
接通電源...
設備檢查...
裝載系統...
機器已經正常打開,請操作...
>>>按下重啓按鈕:>>>
技嘉主板現在正在重新啓動機器,請等候..
機器已經正常打開,請操作

Process finished with exit code 0

還有廚師做飯的案例也是命令模式的典型場景。
在這裏插入圖片描述

總結

命令模式的核心思想就是將命令或者請求封裝成對象,分離請求調用者和請求最終執行者。

優點:
將請求調用者和執行者解耦,適用於底層接口封裝,可以通過只增加類就可以實現接口擴展,不需要修改原來的代碼。

缺點:
如果存在較多的命令或者請求,需要較多的命令類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章