行為型模式:命令模式

LieBrother發表於2019-02-22

LieBrother原文:
行為型模式:命令模式

景

十一大行為型模式之三:命令模式。

簡介

姓名 :命令模式

英文名 :Command Pattern

價值觀 :軍令如山

個人介紹

Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.
將一個請求封裝成一個物件,從而讓你使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。
(來自《設計模式之禪》)

你要的故事

作為一個程式猿,我們每天都在經歷著命令模式,技術經理把需求任務分配給工程師開發,有時因為第三方或者其他不可抗拒的因素導致需求停止開發。這種工作模式就是命令模式。好了,開始故事了。小明在 XX 科技公司做一個安靜的程式猿,有一天技術經理給他分配了一個任務:新增黑名單,也就是在他們系統的某個模組裡面可以手工對電話打黑名單標籤的功能。小明接到任務後就立馬開發,在開發了 2 天之後,因為戰略原因,技術經理大明暫停了這個開發任務,接下來我們通過非命令模式和命令模式 2 種程式碼實現來體現這個過程。在這個場景中,為了簡單,我們假定技術經理大明手下只有小明一個開發人員。

非命令模式

非命令模式也就是不使用命令模式的程式碼實現。程式碼中,我們出現了 Developer 開發人,開發同學是接受技術經理傳達的任務,技術經理讓他開發哪個需求就開發哪個需求,如果專案有問題需要中斷,也需要技術經理評估後傳達給開發同學,所以 Developer 有 2 個方法,分別是 develop() 開發需求和 suspend() 暫停需求。 Requirement 則為需求類,TechnicalManager1 則為技術經理類,他有一個方法 action(),通過這個方法來指定開發同學開發任務或者暫停任務。

public class NoCommandTest {

    public static void main(String[] args) {
        Developer xiaoMing = new Developer("小明");
        Requirement requirement = new Requirement("新增黑名單");
        TechnicalManager1 technicalManager2 = new TechnicalManager1("大明");
        technicalManager2.setDeveloper(xiaoMing);
        technicalManager2.action(requirement, "develop");
        System.out.println("開發了 2 天,需求變故,需要暫停。。。");
        technicalManager2.action(requirement, "suspend");
    }

}

/**
 * 開發人員
 */
class Developer {

    private String name;

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

    public void develop(Requirement requirement) {
        System.out.println(this.name + " 開始開發需求:" + requirement.getName());
    }

    public void suspend(Requirement requirement) {
        System.out.println(this.name + " 停止開發需求:" + requirement.getName());
    }

    public String getName() {
        return name;
    }

}

/**
 * 需求
 */
class Requirement {
    private String name;

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

    public String getName() {
        return name;
    }

}

/**
 * 技術經理
 */
class TechnicalManager1 {

    private String name;

    private Developer developer;

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

    public void setDeveloper(Developer developer) {
        this.developer = developer;
    }

    public void action(Requirement requirement, String type) {
        if ("develop".equals(type)) {
            this.developer.develop(requirement);
        } else if ("suspend".equals(type)) {
            this.developer.suspend(requirement);
        }
    }

}

列印結果:
小明 開始開發需求:新增黑名單
開發了 2 天,需求變故,需要暫停。。。
小明 停止開發需求:新增黑名單

通過程式碼,我們可以發現技術經理和開發同學是強依賴關係。如果技術經理下達了一個任務,要求小明寫一下週報,這時候得怎麼寫?是不是小明需要一個寫週報的方法,大明也需要新增一個處理事務型別?有沒有更好的方法讓技術經理不需要做任何改變?命令模式就來解決這個問題。

命令模式

在這個例子中,不管大明叫小明做什麼事情,其實都是一樣的,就是下達任務命令,讓小明去執行命令。我們可以利用命令模式把下達任務這個抽象起來,當做父類,下達開發命令、下達暫停命令、下達寫週報等等都是不同的子命令。程式碼如下。

public class CommandTest {

    public static void main(String[] args) {
        Developer xiaoMing = new Developer("小明");
        Command developCommand = new DevelopCommand(xiaoMing);
        Command suspendCommand = new SuspendCommand(xiaoMing);
        Requirement requirement = new Requirement("新增黑名單");
        TechnicalManager2 technicalManager = new TechnicalManager2("大明");
        technicalManager.setCommand(developCommand);
        technicalManager.action(requirement);
        System.out.println("開發了 2 天,需求變故,需要暫停。。。");
        technicalManager.setCommand(suspendCommand);
        technicalManager.action(requirement);

    }

}

/**
 * 命令
 */
abstract class Command {

    protected Developer developer;

    public Command(Developer developer) {
        this.developer = developer;
    }

    public abstract void execute(Requirement requirement);
}

/**
 * 開始開發
 */
class DevelopCommand extends Command {

    public DevelopCommand(Developer developer) {
        super(developer);
    }

    @Override
    public void execute(Requirement requirement) {
        this.developer.develop(requirement);
    }
}

/**
 * 開發中斷
 */
class SuspendCommand extends Command {

    public SuspendCommand(Developer developer) {
        super(developer);
    }

    @Override
    public void execute(Requirement requirement) {
        this.developer.suspend(requirement);
    }
}

/**
 * 技術經理
 */
class TechnicalManager2 {

    private String name;
    private Command command;

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

    public void action(Requirement requirement) {
        this.command.execute(requirement);
    }

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

列印結果:
小明 開始開發需求:新增黑名單
開發了 2 天,需求變故,需要暫停。。。
小明 停止開發需求:新增黑名單

程式碼中用 Command 來抽象下達任務,而技術經理 TechnicalManager2 並沒有和 Developer 有直接的關係,而是 TechnicalManager2 和 Command 建立的聯絡,Command 和 Developer 建立了聯絡。這樣子把大明和小明的強依賴關係給剝離開,而新增一個下達寫週報的任務也很簡單,在 Developer 中新增一個處理寫週報的方法,新增一個寫週報的 Command 子類,就可以了,TechnicalManager2 如上面所願不用修改。這就是完整的一個命令模式程式碼。

程式碼:
Command Pattern

總結

從文章中我們就可以看到,利用命令模式能夠進行類的解耦,讓呼叫者和接受者沒有任何關係,也通過對行為的抽象,讓新增其他行為變得清晰容易,也就是可擴充套件性大大增加

參考資料:《大話設計模式》、《設計模式之禪》

推薦閱讀:

公眾號之設計模式系列文章

希望文章對您有所幫助,設計模式系列會持續更新,感興趣的同學可以關注公眾號:LieBrother,第一時間獲取文章推送閱讀,也可以一起交流,交個朋友。

相關文章