設計模式(9):命令模式
命令模式:
定義:
將一個請求封裝成一個物件,從而讓你使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。
通用類圖:
Receiver接受者角色:
該角色就是幹活的角色,命令傳遞到這裡是應該被執行的
Command命令角色
需要執行的所有命令都在這裡宣告
Invoker呼叫者角色
接收到命令並執行命令。
優缺點:
優點:
類間解耦
呼叫者角色與接受者角色之間沒有任何依賴關係,呼叫者實現功能時只需要呼叫Command抽象類的execute方法就可以,不需要了解到底是哪個接受者執行
可擴充套件性
Command的子類可以非常容易的擴充套件,而呼叫者Invoker和高層次的Client不產生嚴重的程式碼耦合
命令模式結合其他模式會更優秀
命令模式可以結合責任鏈模式,實現命令族解析任務;結合模板方法模式,則可以減少Command子類的膨脹問題。
缺點:
如果有N個命令,Command的子類就是N個,容易膨脹。
舉個例子:
實現一個專案,該專案的成員分工採用了常規的分工方式:需求組、美工組、程式碼組
abstract class Group { public abstract void find(); public abstract void add(); public abstract void delete(); public abstract void change(); public abstract void plan(); } // 需求組 class RequirementGroup extends Group { public void find() { System.out.println("找到需求組---"); } // 增加一項需求 public void add() { System.out.println("客戶要求增加一項需求---"); } // 客戶要求刪除一項需求 public void delete() { System.out.println("客戶要求刪除一項需求---"); } public void change() { System.out.println("客戶要求修改一項需求---"); } public void plan() { System.out.println("客戶要求變更計劃---"); } } // 美工組 class PageGroup extends Group { public void find() { System.out.println("找到美工組---"); } public void add() { System.out.println("客戶要求增加一個頁面---"); } public void delete() { System.out.println("客戶要求刪除一個頁面---"); } public void change() { System.out.println("客戶要求修改一個頁面---"); } public void plan() { System.out.println("客戶要求頁面變更計劃---"); } } class CodeGroup extends Group { public void find() { System.out.println("找到程式碼組---"); } public void add() { System.out.println("客戶要求增加一項功能---"); } public void delete() { System.out.println("客戶要求刪除一項功能---"); } public void change() { System.out.println("客戶要求修改一項功能---"); } public void plan() { System.out.println("客戶要求程式碼變更計劃---"); } } public class Client { public static void main(String[] args) { System.out.println("----------客戶要求增加一項需求----------"); Group rg = new RequirementGroup(); rg.find(); rg.add(); rg.plan(); } }
在原有類圖上增加了一個Invoker類,其作用是根據客戶的命令安排不同的組員進行工作。但是在系統設計中,字串沒有約束力,根據字串判斷相關的業務邏輯不是一個優秀的解決方案。
解決方案是對客戶發出的命令進行封裝,每個命令是一個物件,避免客戶、負責人、組員之間的交流誤差,封裝後的結果就是客戶只要說一個命令,我的專案組就立刻開始啟動,不用思考、解析命令字串。
Command抽象類只有一個方法execute,其作用就是執行命令,子類非常堅決的解決該命令。
Command抽象類:客戶發給我們的命令,定義三個工作組的成員變數,供子類使用;定義一個抽象方法execute,由子類實現。
Invoker實現類:專案接頭負責人,setCommand接收客戶發給我們的命令,action方法是執行客戶的命令
抽象命令類:
abstract class Command {
protected RequirementGroup rg = new RequirementGroup();
protected PageGroup pg = new PageGroup();
protected CodeGroup cg = new CodeGroup();
public abstract void execute();
}
需要什麼功能就 繼承該類,並實現execute方法
增加需求:
// 增加需求的命令
class AddRequirementCommand extends Command {
// 執行增加一項需求的命令
public void execute() {
super.rg.find();
super.rg.add();
super.rg.plan();
}
}
刪除一個頁面:
class DeletePageCommand extends Command {
// 執行刪除一個頁面的命令
public void execute() {
super.pg.find();
super.pg.delete();
super.pg.plan();
}
}
Invoker類:
class Invoker {
private Command command;
public void setCommand(Command _command) {
this.command = _command;
}
// 執行客戶的命令
public void action() {
this.command.execute();
}
}
增加一個需求Client:
public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
System.out.println("-------客戶要求增加一項需求---------");
Command command = new AddRequirementCommand();
invoker.setCommand(command);
invoker.action();
}
}
刪除一個頁面Client:
public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
System.out.println("-------客戶要求增加一項需求---------");
// Command command = new AddRequirementCommand();
Command command = new DeletePageCommand();
invoker.setCommand(command);
invoker.action();
}
}
只需要修改很少就可以實現功能的轉變。