設計模式-----命令模式

設計模式—–命令模式

個人博客,想要搭建個人博客的可以進來看看: http://www.ioqian.top/


命令模式 , 將請求封裝成對象,以便使用不同的請求,隊列或日誌來參數化其他對象,命令模式也支持可撤銷的操作

設計模式系列源碼: https://github.com/liloqian/DesiginModeDemo

背景
現在有一個遙控器,上面有1個按鈕,我們要根據不同的請求來控制不同的電器,比如說可以控制風扇,點燈等,這裏我們就可以引入命令模式

在面向對象的程序設計中,一個對象調用另一個對象,一般情況下的調用過程是:創建目標對象實例;設置調用參數;調用目標對象的方法。
但在有些情況下有必要使用一個專門的類對這種調用過程加以封裝,我們把這種專門的類稱作command類。

1.下面先大概看一下UML
此處輸入圖片的描述

  • Command ,是所有命令的一個接口,調用Command中的execute()方法就可以讓接受者進行相關的動作
  • Receiver , 動作的最終執行者 ,比如我們背景中的風扇 , 電燈,打開風扇,打開電燈等動作最終只可能由電燈風扇自身實現
  • CreateCommand ,持有Receiver的引用,繼承了Command接口,在Command接口的execute()方法中直接調用Receiver的具體動作
  • Invoker , 調用者,持有一個命令接口,當客戶調用時直接調用命令接口的execute()方法

2.下面來看具體的代碼
Receiver,這裏實現了2個命令接收者,分別是風扇和電燈

/**Receiver  具體的命令接收者,接受者指導如何進行必要的工作,也是真正執行命令的方法*/
public class Light {
    //實現了這個方法都可以成爲命令接收者,這個方法是真正執行命令的方法,對應上圖中的action()方法
    public void on(){
        System.out.println(this.toString()+":  turn on the light");
    }
    @Override
    public String toString() {
        return "I-am-light";
    }
}
/**另外一個接受者*/
public class Fan {
    public void on(){
        System.out.println(this.toString()+":  turn on the fan");
    }
    @Override
    public String toString() {
        return "I-am-fan";
    }
}

Command接口

/**命令接口,所以的遙控器控制的電器命令都要實現這個接口*/
public interface Command {
    public void execute();
}

CreateCommand,實現了Command接口的具體命令,持有接受者Receiver的引用

/**CreateCommand*/
public class LightCommand implements Command {
    //持有一份接受者Receiver中Light的引用
    Light light ;
    public LightCommand(Light light) {
        this.light = light;
    }
    @Override
    public void execute() {
        light.on();
    }
}
/**和上面的一樣*/
public class FanCommand implements Command {
    Fan fan;
    public FanCommand(Fan fan) {
        this.fan = fan;
    }
    @Override
    public void execute() {
        fan.on();
    }
}

Invoker

/**Invoker 持有一個命令對象,當點擊按鈕時就執行命令對象的方法*/
public class SimpleRemoteControl {
    //命令對象
    Command command;
    //點擊按鈕後調用此方法去調用命令對象實現的方法
    public void buttonPressed(){
        command.execute();
    }
    public void setCommand(Command command) {
        this.command = command;
    }
}

Client ,直接在Main測試中進行

public class Main {
    public static void main(String[] args) {
        //實例化一個命令調用者
        SimpleRemoteControl remote = new SimpleRemoteControl();
        //電燈命令
        LightCommand lightOn = new LightCommand(new Light());
        //設置電燈命令,點擊按鈕去執明LightCommand的方法
        remote.setCommand(lightOn);
        remote.buttonPressed();
        //下面的和上面的一樣
        FanCommand fanOn = new FanCommand(new Fan());
        remote.setCommand(fanOn);
        remote.buttonPressed();
    }
}
//結果 , 我們通過傳入不同的命令參數可以執行不同的請求
I-am-light:  turn on the light
I-am-fan:  turn on the fan

Process finished with exit code 0

上面的模型中也可以不必一定要有Receiver,可以把具體的動作放在ConcreteCommand中

3.命令模式的用途,隊列請求

新建一個專門處理請求對象的線程,從隊列獲取請求對象(就是請求封裝的對象),進行處理;在其他線程中把請求封裝成對象加入這個隊列

此處輸入圖片的描述

4.命令模式的要點

  • 命令模式將要發出請求的對象和執行請求的對象解耦,執行請求的對象不關心請求的具體內容,只要把具體的請求封裝成請求的對象就可以了
  • 被解耦的兩者之間是通過命令對象進行溝通的,命令對象封裝了接收者和一個或一組動作
  • 調用者通過調用命令對象的execute()方法使得接受者的動作被執行
  • 命令可以被撤銷,做法是實現一個undo()方法來回到execute()之前的狀態,undo()和execute()的具體實現一樣
  • 實際中,使用聰明命令對象,而不是把工作給了接受者,就是前面說的,不必一定要有Receiver,可以把具體的動作放在ConcreteCommand中
發佈了75 篇原創文章 · 獲贊 18 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章