設計模式 | 命令模式(Command)

定義:

將一個請求封裝爲一個對象,從而使你可用不一樣的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤銷的操做。

結構:(書中圖,侵刪)

 

一個抽象命令類
若干具體命令類
若干具體執行命令的接受者類
一個傳話類(Invoker)
並無客戶類,都是直接經過傳話類進行請求的
 

實例:

說到命令就想到了皇上,而後想到一般客戶都不止一個,但皇上只有一個,但不重要,重點不在這。
皇上下命令,一般也是直接對身邊的太監總管說,他不會親自去找到某我的去下達命令,何況他可能還真不認識底下的那些個太監宮女。
so...這裏用命令模式也再合適不過。
我作了一些改動,先貼上代碼再細說。

 宮女類(接受者):java

package designpattern.command;

/*
 * 宮女
 */
public class Maid {
    String name;

    public Maid(String name) {
        this.name = name;
    }

    public void clean() {
        System.out.println(this.name + ":打掃衛生");
    }
}

太監類(接受者):ide

package designpattern.command;

/*
 * 太監
 */
public class Eunuch {
    String name;

    public Eunuch(String name) {
        this.name = name;
    }

    public void carrySedanChair() {
        System.out.println(this.name + ":擡轎子");
    }
}

抽象命令接口:ui

package designpattern.command;

public interface Command {
    public void execute();
}

打掃命令類(具體命令類):this

package designpattern.command;

public class CleanCommand implements Command {
    private Maid maid;

    public CleanCommand(Maid maid) {
        this.maid = maid;
    }

    @Override
    public void execute() {
        maid.clean();
    }

}

擡轎子命令類(具體命令類):spa

package designpattern.command;

public class CarrySedanChairCommand implements Command {
    private Eunuch eunuch;

    public CarrySedanChairCommand(Eunuch eunuch) {
        this.eunuch = eunuch;
    }

    @Override
    public void execute() {
        eunuch.carrySedanChair();

    }
}

太監總管類(Invoker):設計

package designpattern.command;

import java.util.ArrayList;
import java.util.List;

public class ManagerEunuch {
    private List<Command> commands = new ArrayList<Command>();

    public void setCommand(Command command) {
        this.commands.add(command);
    }

    public void notifyIt() {
        for (Command command : commands) {
            command.execute();
        }
    }
}

客戶端:日誌

package designpattern.command;

public class Client {
    public static void main(String[] args) {
        Maid xiaocui = new Maid("小翠");
        Maid xiaohua = new Maid("小花");
        Eunuch xiaozhuozi = new Eunuch("小卓子");
        Eunuch xiaoguizi = new Eunuch("小貴子");

        Command cleanCommand1 = new CleanCommand(xiaocui);
        Command cleanCommand2 = new CleanCommand(xiaohua);

        Command carrySedanChairCommand1 = new CarrySedanChairCommand(xiaozhuozi);
        Command carrySedanChairCommand2 = new CarrySedanChairCommand(xiaoguizi);

        ManagerEunuch ligongong = new ManagerEunuch();
        ligongong.setCommand(cleanCommand1);
        ligongong.setCommand(cleanCommand2);
        ligongong.setCommand(carrySedanChairCommand1);
        ligongong.setCommand(carrySedanChairCommand2);
        ligongong.notifyIt();

    }
}

結果輸出:code

小翠:打掃衛生
小花:打掃衛生
小卓子:擡轎子
小貴子:擡轎子

 

我本來想着命令的執行者(Receiver)應該有不少種,好比個人例子中,有宮女和太監。可是個人實際感覺是,這更合適對應單一的執行者。
雖然我實現了多個執行者,但其實執行者和具體的命令間是深度耦合的,好比打掃的命令(CleanCommand)擁有一個宮女(執行者)的實例。
若是太監也要打掃就要新建另一個擁有太監實例的打掃命令類,雖然你能夠抽象出一個執行者父類,讓他們都持有這個父類的實例,但你不能調用father.clean(),除非你在父類中定義這個方法,但每當子類增長方法,父類都要相應增長,這顯然不是一個好的設計。我暫時並無想到一個好的方式去解決這個問題,因此私覺得,可能更適合用於單一類型的執行者。
emmm,我剛剛又想了想,多是我這個例子中執行者的分類有問題,可能一般每一個執行者類的工做範圍相差比較大,像我舉的例子中,宮女和太監可能有50%的工做是重合的,若是咱們以具體的工做類型來分類,好比御膳房的,洗衣房的,這樣分,就不會有問題了。算是走進了思惟的誤區吧。引覺得戒。
 

總結:

我以爲書中寫的幾點挺好的,這邊引用過來吧。
第一,它能較容易地設計一個命令隊列;
第二,在須要的狀況下,能夠較容易地將命令記入日誌;
第三,容許接收請求的一方決定是否要否決請求
第四,能夠容易地實現對請求的撤銷和重作;
第五,因爲 加進新的具體命令類不影響其餘類,所以增長新的具體命令類很容易。
最關鍵的優勢就是命令模式把請求一個操做的對象與知道怎麼執行一個操做的對象分割開。
相關文章
相關標籤/搜索