命令模式(Command Pattern)。

孤芳不自賞發表於2017-08-23

命令模式是一個高內聚的模式,其定義為:

將一個請求封裝成一個物件,從而讓你使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。

通用程式碼:

  • Receiver接收者角色

該角色就是幹活的角色,命令傳遞到這裡是應該被執行的。

  • Command命令角色

需要執行的所有命令都在這裡宣告。

  • Invoker呼叫者角色

接收到命令,並執行命令。

通用Receiver類

public abstract class Receiver {

// 抽象接收者,定義每個接收者都必須完成的業務

public abstract void doSomething();

}

很奇怪,為什麼Receiver是一個抽象類?那是因為接收者可以有多個,有多個就需要定義一個所有特性的抽象集合——抽象的接收者。

具體的Receiver類

pubic class ConcreteReciver1 extends Receiver {

// 每個接收者都必須處理一定的業務邏輯

public void doSomething(){}

}

pubic class ConcreteReciver2 extends Receiver {

// 每個接收者都必須處理一定的業務邏輯

public void doSomething(){}

}

接收者可以是N個,這要依賴業務的具體定義。命令角色是命令模式的核心。

抽象的Command類

public abstract class Command {

// 定義一個子類的全域性共享變數;

protected final Receiver receiver;

// 實現類必須定義一個接收者

public Command(Receiver _receiver) {

this.receiver = _receiver;

}

// 每個命令類都必須有一個執行命令的方法

public abstract void execute();

}

根據環境的需求,具體的命令類也可以有N個。

具體的Command類

public class ConcreteCommand1 extends Command {

// 宣告自己的的預設接收者

public ConcreteCommand1(){

super(new ConcreteReciver1());

}

// 設定新的接收者

public ConcreteCommand1(Receiver _receiver) {

super(_receiver);

}

// 必須實現一個命令

public void execute(){

// 業務處理

super.receiver.doSomething();

}

}


public class ConcreteCommand2extends Command {

// 宣告自己的的預設接收者

public ConcreteCommand2(){

super(new ConcreteReciver2());

}

// 設定新的接收者

public ConcreteCommand2Receiver _receiver) {

super(_receiver);

}

// 必須實現一個命令

public void execute(){

// 業務處理

super.receiver.doSomething();

}

}


呼叫者Invoker類

public class Invoker {

private Command command;

// 受氣包,接受命令

public void setCommand(Command _command) {

this.command = _command;

}

// 執行命令

public void action() {

this.command.execute();

}

}

場景類

public class Client {

public static void main(String[] args) {

// 首先宣告呼叫者Invoker

Invoker invoker = new Invoker();

// 定義一個傳送給接收者的命令

Command command = new ConcreteCommand1();

// 把命令交給呼叫者去執行

invoker.setCommand(command);

invoker.action();

}

}

優點:

  • 類間解耦

呼叫者角色與接收者角色之間沒有任何依賴關係,呼叫者實現功能時只需呼叫Command抽象類的execute方法就可以,不需要了解到底是哪個接收者執行。

  • 可擴充套件性

Command的子類可以非常容易的擴充套件,而呼叫者Invoker和高層次的模組Client不產生嚴重的程式碼耦合。

  • 命令模式結合其他模式會更優秀

命令模式可以結合責任鏈模式,實現命令族解析任務,結合模板方法模式,則可以減少Command子類的膨脹問題。

缺點:

命令模式也是有缺點的,請看Command的子類:如果有N個命令,問題就出來了,Command的子類就可不是幾個,而是N個,這個類膨脹的非常大,這個就需要讀者在專案中慎重考慮使用。

使用場景:

只要你認為是命令的地方就可以採用命令模式。例如,在GUI開發中,一個按鈕的點選是一個命令,可以採用命令模式;模擬DOS命令的時候,當然也要採用命令模式;觸發——反饋機制等。

擴充套件:

  • 反悔問題

有兩種方法解決:一是結合備忘錄模式還原最後狀態,該方法適合接收者為狀態的變更情況,而不適合事件處理;二是通過增加一個新的命令,實現事件的回滾。

示例程式碼:

抽象組

public abstract class Group {

// 甲乙雙方分開辦公,如果你要和某個組討論,你首先要找到這個組

public abstract void find();

// 被要求增加功能

public abstract void add();

// 被要求刪除功能

public abstract void delete();

// 被要求修改功能

public abstract void change();

// 被要求給出所有的變更計劃

public abstract void plan();

// 每個接收者都要對直接執行的任務可以回滾

public void rollBack() {

// 根據日誌進行回滾

}

}

需求組
 

public class RequirementGroup extends Group {

// 客戶要求需求組過去和他們談

public void finid(){

System.out.println("找到需求組...");

}

// 客戶要求增加一項需求

public void add() {

System.out.println("客戶要求增加一項需求...");

}

// 客戶要求修改一項需求

public void change() {

System.out.println("客戶要求修改一項需求...");

}

// 客戶要求刪除一項需求

public void delete() {

System.out.println("客戶要求刪除一項需求...");

}

// 客戶要求給出變更計劃

public void plan() {

System.out.println("客戶要求需求變更計劃");

}

}

美工組(PageGroup)、程式碼組(CodeGroup)程式碼與需求組(RequirementGroup)類似,故省略。

抽象命令類

public abstract class Command {

// 把三個組都定義好,子類可以直接使用

protected RequirementGroup rq = new RequirementGroup(); // 需求組

protected PageGroup pg = new PageGroup(); // 美工組

protected CodeGroup cg = new CodeGroup(); // 程式碼組

// 只有一個方法,你要我做什麼事情

public abstract void execute();

}

增加需求的命令
 

public class AddRequirementCommand extends Command {

// 執行增加一項需求的命令

public void execute() {

// 找到需求組

super.rg.find();

// 增加一份需求

super.rg.add();

// 頁面也要增加

super.pg.add();

// 功能也要增加

super.cg.add();

// 給出計劃

super.rg.plan();

}

}

撤銷命令

public class CancelDeletePageCommand extends Command {

// 撤銷刪除一個頁面的命令

public void execute() {

super.pg.rollBack();

}

}

負責人
 

public class Invoker {

// 什麼命令

private Command command;

// 客戶發出命令

public void setCommand(Command command) {

this.command = command;

}

// 執行客戶的命令

public void action() {

this.command.execute();

}

}

增加一項需求

public class Client {

public static void main(String[] args) {

// 定義我們的接頭人

Invoker xiaoSan = new Invoker(); // 接頭人就是小三

// 客戶要求增加一項需求

System.out.println("------------------------客戶要求增加一項需求---------------");

// 客戶給我們下命令來

Command command =new AddRequirementCommand();

// 接頭人接收命令

xiaoSan.setCommand(command);

// 接頭人執行命令

xiaoSan.action();

}

}


public class ConcreteCommand1 extends Command {

// 對哪個Receiver類進行命令處理

private Receiver receiver;

// 建構函式傳遞接收者

public ConcreteCommand1(Receiver _receiver) {

this.receiver = _receiver;

}

// 必須實現一個命令

public void execute(){

// 業務處理

this.receiver.doSomething();

}

}

}

 

相關文章