美文网首页
设计模式-命令模式

设计模式-命令模式

作者: 小的橘子 | 来源:发表于2019-10-12 18:07 被阅读0次

    命令模式介绍

    命令模式(Command Pattern),是行为型模式之一。

    命令模式定义

    将一个请求封装成一个对象,从而使用户使用不同的请求把客户端参数化;对请求排队或记录请求日志,以及支持可撤销操作。

    命令模式使用场景

    操作可以看做命令的时候,且需要支持撤销,批量执行等操作时。

    命令模式 UML 类图


    角色介绍:

    • Receiver:接收者角色,就是执行具体逻辑的角色。
    • Command:命令角色。
    • ConcreteComand:具体命令角色,负责调用接收者对应的具体方法。
    • Invoker:请求者角色,负责调用命令对象的执行具体的请求。
    • Client:客户端角色。

    命令模式示例

    显示生活中比较形象的就是餐馆的运行机制:

    顾客在某团点一碗面条(创建命令) -> 店员确认订单 -> 厨师很快做好了一碗面条(执行请求)。顾客不知道将由谁来做这碗面,店员也不知道,厨师不知道是谁点了这碗面,只知道做完面就可以休息了。是不是与命令模式很相像?
    接收者角色
    接收者也就是真正做事的,这里就是厨师

    public class Cook {
        public void cookNoodles() {
            System.out.println("做面条中...");
        }
    
        public void cookCake() {
            System.out.println("做饼中...");
        }
    }
    

    命令角色

    public interface Command {
        void execute();
    }
    

    具体命令角色

    1. 做面条的命令
    public class NoodlesCommand implements Command {
        private Cook receiver;
    
        public NoodlesCommand(Cook receiver) {
            this.receiver = receiver;
        }
    
        @Override
        public void execute() {
            receiver.cookNoodles();
        }
    }
    
    1. 做饼的命令
    public class CakeCommand implements Command {
        private Cook receiver;
    
        public CakeCommand(Cook receiver) {
            this.receiver = receiver;
        }
    
        @Override
        public void execute() {
            receiver.cookCake();
        }
    }
    

    调用者角色
    店员负责记录订单并在电脑上按提交按钮。

    public class Waiter {
        Command command;
    
        public void setCommand(Command command) {
            this.command = command;
        }
    
        public void action() {
            command.execute();
        }
    }
    

    客户端角色

    public class Client {
        public static void main(String[] args) {
            Cook cook = new Cook();
            NoodlesCommand noodlesCommand = new NoodlesCommand(cook);
            Waiter waiter = new Waiter();
            // 下单面条
            waiter.setCommand(noodlesCommand);
            waiter.action();
    
            CakeCommand cakeCommand = new CakeCommand(cook);
            // 下单饼
            waiter.setCommand(cakeCommand);
            waiter.action();
        }
    }
    

    执行结果:

    做面条中...
    做饼中...
    

    可见客户的订餐正常得到执行。不过上面依然可以优化,没必要顾客每点一条店员就确认一下,完全可以顾客点好所有,店员统一确认。

    店员优化中

    public class Waiter {
        List<Command> commands = new ArrayList<>();
    
        public void addCommand(Command command) {
            commands.add(command);
        }
    
        public void removeCommand(Command command) {
            commands.remove(command);
        }
    
        public void action() {
            for (Command command : commands) {
                command.execute();
            }
        }
    }
    

    客户端优化

    public class Client {
        public static void main(String[] args) {
            Cook cook = new Cook();
            NoodlesCommand noodlesCommand = new NoodlesCommand(cook);
            CakeCommand cakeCommand = new CakeCommand(cook);
            Waiter waiter = new Waiter();
            // 来两饼一碗面条
            waiter.addCommand(noodlesCommand);
            waiter.addCommand(cakeCommand);
            waiter.addCommand(cakeCommand);
            waiter.action();
        }
    }
    

    可以看到命令模式使客户端与具体执行者的耦合性降低,对于客户端需求更容易扩展。

    命令模式总结

    优点
    1.它能较容易地设计一个命令队列;
    2.在需要的情况下,可以较容易地将命令记入日志;
    3.允许接受请求的一方决定是否要否决请求;
    4.可以容易的实现对请求的撤销和重做;
    5.由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易;
    6.命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分隔开;

    注意:敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般不要着急去实现,事实上,在需要的时候通过重构事项这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
    缺点
    使用命令模式可能会导致某些系统有过多的具体命令类。

    相关文章

      网友评论

          本文标题:设计模式-命令模式

          本文链接:https://www.haomeiwen.com/subject/yptcmctx.html