Java設計模式之命令模式

介紹java

命令模式是一種行爲型設計模式。在命令模式中,全部的請求都會被包裝成爲一個對象。設計模式

參考了一下其餘關於命令模式的文章,其中有談到說是能夠用不一樣的請求對客戶進行參數化。對這句話的理解是,由於將請求封裝成爲對象,因此客戶的全部操做,其實就是多個命令類的對象而已,即參數化了。

命令模式的最大的特色就是將請求的調用者與請求的最終執行者進行了解耦。調用者須要關心的僅僅是請求對象是否被執行了,對於請求對象是如何執行的,對什麼進行操做的,通通不須要關心。ide

原理:命令模式中,通常有以下幾個角色:ui

  • command:命令的抽象接口,其中包含execute方法。根據業務需求,有的還會包含其餘通用方法如undo等。
  • concreteCommand:具體的命令實現類。每一種請求,都會映射一個具體的命令實現類。對於每一個類,都會實現execute方法,而且依賴receiver,也就是接收者對象。execute方法中,通常就是調用接收者對象的對應方法,從而實現對請求的最終處理。
  • receiver:請求的接收者,也是請求的最終的執行者,被命令實現類所依賴。
  • invoker:請求的調用者。調用者會調用全部傳入的命令對象的execute方法,開啓命令的執行,可是不會與最終的執行者receive耦合,二者中間是經過命令實現類進行聯繫和溝通的。
  • client:進行接收者對象和命令對象的建立,並創建二者之間的聯繫。

適用場景:涉及到「命令」、「操做」或者「控制」的場景,通常都是命令模式的適用場景。this

  • 餐廳點菜的過程,消費者(client)說要吃某幾種菜(命令對象),趕快作好端上來。服務員(invoker)會記錄全部點過的菜品(保存全部的命令對象),而後將訂單給後廚說,按照單子作(調用全部命令對象的execute)。以後就會啓動每一道菜品的製做流程。對於菜品如何烹製,與服務員是沒有關係的,二者不耦合。
  • 遙控器的運行過程也能夠理解成是一種命令模式的應用。假設有一個智能家居的遙控器,在面板上,能夠控制電燈的開關,空調的開關(各類命令對象)。遙控器就是invoker的角色,負責實際命令的調用。而最終命令的執行,則是各類電器(receiver)來進行的。

案例

    背景:咱們以顧客點菜爲例。顧客有一個菜單(invoker),可以預約甜點、牛奶、水果,取消甜點、牛奶、水果等操做。

    實現:

命令接口:spa

/**
 * @program: test
 * @description: 命令
 * @author: xingcheng
 * @create: 2018-09-02 15:16
 **/
public interface Command {

    /**
     * 執行命令
     */
    void execute();
    
}

定義receiver:設計

/**
 * @program: test
 * @description: 水果
 * @author: xingcheng
 * @create: 2018-09-02 15:18
 **/
public class Fruit {

    /**
     * 點一份水果
     */
    void orderFruit(){
        System.out.println("來一份水果");
    }

    /**
     * 取消水果
     */
    void cancelFruit(){
        System.out.println("取消水果");
    }
}

/**
 * @program: test
 * @description: 牛奶
 * @author: xingcheng
 * @create: 2018-09-02 15:22
 **/
public class Milk {

    /**
     * 點一份牛奶
     */
    void orderMilk(){
        System.out.println("來一份牛奶");
    }
    
    /**
     * 取消牛奶
     */
    void cancelMilk(){
        System.out.println("取消牛奶");
    }
}

/**
 * @program: test
 * @description: 甜點
 * @author: xingcheng
 * @create: 2018-09-02 15:17
 **/
public class Mousse {

    /**
     * 點一份甜點
     */
    void orderMousse(){
        System.out.println("來一份甜點");
    }

    /**
     * 取消甜點
     */
    void cancelMousse(){
        System.out.println("取消甜點");
    }
}

定義具體命令:code

/**
 * @program: test
 * @description: 點一份水果
 * @author: xingcheng
 * @create: 2018-09-02 15:29
 **/
public class OrderFruit implements Command{
    
    private Fruit fruit;

    public OrderFruit(Fruit fruit) {
        this.fruit = fruit;
    }

    /**
     * 執行命令
     */
    @Override
    public void execute() {
        fruit.orderFruit();
    }
}

/**
 * @program: test
 * @description: 點一份牛奶
 * @author: xingcheng
 * @create: 2018-09-02 15:25
 **/
public class OrderMilk implements Command{
    
    private Milk milk;

    public OrderMilk(Milk milk) {
        this.milk = milk;
    }

    /**
     * 執行命令
     */
    @Override
    public void execute() {
        milk.orderMilk();
    }
}

/**
 * @program: test
 * @description: 點一份甜點
 * @author: xingcheng
 * @create: 2018-09-02 15:31
 **/
public class OrderMousse implements Command{
    
    private Mousse mousse;

    public OrderMousse(Mousse mousse) {
        this.mousse = mousse;
    }

    /**
     * 執行命令
     */
    @Override
    public void execute() {
        mousse.orderMousse();
    }
}

/**
 * @program: test
 * @description: 取消水果
 * @author: xingcheng
 * @create: 2018-09-02 15:30
 **/
public class CancelFruit implements Command {
    
    private Fruit fruit;

    public CancelFruit(Fruit fruit) {
        this.fruit = fruit;
    }

    /**
     * 執行命令
     */
    @Override
    public void execute() {
        fruit.cancelFruit();
    }
}

/**
 * @program: test
 * @description: 取消牛奶
 * @author: xingcheng
 * @create: 2018-09-02 15:27
 **/
public class CancelMilk implements Command{
    
    private Milk milk;

    public CancelMilk(Milk milk) {
        this.milk = milk;
    }

    /**
     * 執行命令
     */
    @Override
    public void execute() {
        milk.cancelMilk();
    }
}

/**
 * @program: test
 * @description: 取消甜點
 * @author: xingcheng
 * @create: 2018-09-02 15:32
 **/
public class CancelMousse implements Command {
    
    private Mousse mousse;

    public CancelMousse(Mousse mousse) {
        this.mousse = mousse;
    }

    /**
     * 執行命令
     */
    @Override
    public void execute() {
        mousse.cancelMousse();
    }
}

定義菜單(invoker)對象

/**
 * @program: test
 * @description: 菜單
 * @author: xingcheng
 * @create: 2018-09-02 15:36
 **/
public class Menu {

    private List<Command> commands;

    public Menu() {
        this.commands = new ArrayList<>();
    }

    /**
     * 記錄顧客須要什麼
     */
    public void writeMenu(Command command){
        commands.add(command);
    }

    /**
     * 將菜單交給廚師
     */
    public void giveCooker(){
        if (commands != null && commands.size() > 0){
            commands.forEach(command -> command.execute());
        }
    }
}

顧客購買:blog

/**
 * @program: test
 * @description: 顧客
 * @author: xingcheng
 * @create: 2018-09-02 15:34
 **/
public class Consumer {
    
    public static void main(String[] args) {
        Fruit fruit = new Fruit();
        Milk milk = new Milk();
        Mousse mousse = new Mousse();

        // 店小二記錄菜單
        System.out.println("店小二記錄菜單----------------------------------------------");
        Menu menu = new Menu();
        menu.writeMenu(new OrderFruit(fruit));
        menu.writeMenu(new OrderMilk(milk));
        menu.writeMenu(new OrderMousse(mousse));
        
        // 店小二將菜單交給廚師
        menu.giveCooker();

        // 顧客取消菜單--太貴了不吃了╭(╯^╰)╮
        System.out.println("顧客取消菜單--太貴了不吃了╭(╯^╰)╮----------------------------");
        Menu menuCancel = new Menu();
        menuCancel.writeMenu(new CancelFruit(fruit));
        menuCancel.writeMenu(new CancelMilk(milk));
        menuCancel.writeMenu(new CancelMousse(mousse));
        menuCancel.giveCooker();

        System.out.println("宏命令----------------------------");
        List<Command> commands = new ArrayList<>();
        commands.add(new CancelFruit(fruit));
        commands.add(new CancelMilk(milk));
        commands.add(new CancelMousse(mousse));
        MutilCommand mutilCommand = new MutilCommand(commands);
        mutilCommand.giveCooker();
    }
    
}

結果:

延伸:

命令模式中有一種擴展,叫作宏命令,能同時進行一組命令的執行。好比遙控器只存在兩個按鍵,一個控制全部電器的開啓,一個控制全部電器的關閉。那麼咱們不須要改動已有的代碼,只要擴展一個組合命令類,其中包含多個命令便可。

/**
 * @program: test
 * @description: 宏命令(組合命令)
 * @author: xingcheng
 * @create: 2018-09-02 15:59
 **/
public class MutilCommand {

    private List<Command> commands;

    public MutilCommand(List<Command> commands) {
        this.commands = commands;
    }

    /**
     * 記錄顧客須要什麼
     */
    public void writeMenu(Command command){
        commands.add(command);
    }

    /**
     * 將菜單交給廚師
     */
    public void giveCooker(){
        if (commands != null && commands.size() > 0){
            commands.forEach(command -> command.execute());
        }
    }
    
}

總結:

命令模式的核心思想就是將命令或者請求封裝成對象,分離請求調用者和請求最終執行者。

優勢:將請求調用者和執行者解耦,適用於底層接口封裝,能夠經過只增長類就能夠實現接口擴展,不須要修改原來的代碼。

缺點:若是存在較多的命令或者請求,須要較多的命令類。

相關文章
相關標籤/搜索