专栏首页邢成的架构笔记Java设计模式之命令模式 原

Java设计模式之命令模式 原

介绍

命令模式是一种行为型设计模式。在命令模式中,所有的请求都会被包装成为一个对象。

参考了一下其他关于命令模式的文章,其中有谈到说是可以用不同的请求对客户进行参数化。对这句话的理解是,因为将请求封装成为对象,所以客户的所有操作,其实就是多个命令类的对象而已,即参数化了。

命令模式的最大的特点就是将请求的调用者与请求的最终执行者进行了解耦。调用者需要关心的仅仅是请求对象是否被执行了,对于请求对象是如何执行的,对什么进行操作的,统统不需要关心。

原理:命令模式中,一般有如下几个角色:

  • command:命令的抽象接口,其中包含execute方法。根据业务需求,有的还会包含其他通用方法如undo等。
  • concreteCommand:具体的命令实现类。每一种请求,都会映射一个具体的命令实现类。对于每个类,都会实现execute方法,并且依赖receiver,也就是接收者对象。execute方法中,一般就是调用接收者对象的对应方法,从而实现对请求的最终处理。
  • receiver:请求的接收者,也是请求的最终的执行者,被命令实现类所依赖。
  • invoker:请求的调用者。调用者会调用所有传入的命令对象的execute方法,开启命令的执行,但是不会与最终的执行者receive耦合,两者中间是通过命令实现类进行联系和沟通的。
  • client:进行接收者对象和命令对象的创建,并建立两者之间的联系。

适用场景:涉及到“命令”、“操作”或者“控制”的场景,一般都是命令模式的适用场景。

  • 餐厅点菜的过程,消费者(client)说要吃某几种菜(命令对象),赶快做好端上来。服务员(invoker)会记录所有点过的菜品(保存所有的命令对象),然后将订单给后厨说,按照单子做(调用所有命令对象的execute)。之后就会启动每一道菜品的制作流程。对于菜品如何烹制,与服务员是没有关系的,两者不耦合。
  • 遥控器的运行过程也可以理解成是一种命令模式的应用。假设有一个智能家居的遥控器,在面板上,可以控制电灯的开关,空调的开关(各种命令对象)。遥控器就是invoker的角色,负责实际命令的调用。而最终命令的执行,则是各种电器(receiver)来进行的。

案例

    背景:我们以顾客点菜为例。顾客有一个菜单(invoker),能够预定甜点、牛奶、水果,取消甜点、牛奶、水果等操作。

    实现:

命令接口:

/**
 * @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("取消甜点");
    }
}

定义具体命令:

/**
 * @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());
        }
    }
}

顾客购买:

/**
 * @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());
        }
    }
    
}

总结:

命令模式的核心思想就是将命令或者请求封装成对象,分离请求调用者和请求最终执行者。

优点:将请求调用者和执行者解耦,适用于底层接口封装,可以通过只增加类就可以实现接口扩展,不需要修改原来的代码。

缺点:如果存在较多的命令或者请求,需要较多的命令类。

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Boot2.0 Oauth2 服务器和客户端配置及原理

    有一个"云冲印"的网站,可以将用户储存在Google的照片,冲印出来。用户为了使用该服务,必须让"云冲印"读取自己储存在Google上的照片。

    chinotan
  • rabbitMQ实现可靠消息投递 原

        RabbitMQ消息的可靠性主要包括两方面,一方面是通过实现消费的重试机制(通过@Retryable来实现重试,可以设置重试次数和重试频率,但是要保证幂...

    chinotan
  • Mybatis通过Interceptor来简单实现影子表进行动态sql读取和写入 续

        继上一篇Mybatis通过Interceptor来简单实现影子表进行动态sql读取和写入 地址:https://my.oschina.net/u/326...

    chinotan
  • 《你必须知道的.NET》读书笔记二:小OO有大原则

    此篇已收录至《你必须知道的.Net》读书笔记目录贴,点击访问该目录可以获取更多内容。

    Edison Zhou
  • 【一起学系列】之命令模式:封装一个简单Jedis?

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

    Kerwin
  • 设计模式-装饰模式

    cwl_java
  • Java外观模式(门面模式Facade)

      外观模式也叫门面模式,是开发过程中使用频率非常高的一种设计模式,但非常容易理解。

    用户4919348
  • Java设计模式-装饰模式

    装饰模式:简单的来说就是动态的给一个对象增加额外的功能,就单纯的新增功能来说会比单一的给一个子类新增功能来的灵活,是跟代理模式中的静态代理模式和动态代理模式十分...

    cwl_java
  • java编程_socket_套接字_网络编程_简易的GUI多线程聊天程序

    ===============================================================

    Hongten
  • AIDL(续)

    http://blog.csdn.net/lxj1137800599/article/details/50998757 这篇文章讲的是在不同的工程文件中实现...

    提莫队长

扫码关注云+社区

领取腾讯云代金券