Java设计模式之命令模式

Wesley13
• 阅读 677

介绍

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

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

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

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

  • 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();
    }
    
}

结果:

Java设计模式之命令模式

延伸:

命令模式中有一种扩展,叫做宏命令,能同时进行一组命令的执行。比如遥控器只存在两个按键,一个控制所有电器的开启,一个控制所有电器的关闭。那么我们不需要改动已有的代码,只要扩展一个组合命令类,其中包含多个命令即可。

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

总结:

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

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

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

点赞
收藏
评论区
推荐文章
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java实现23种设计模式之责任链模式
顾名思义,责任链模式(ChainofResponsibilityPattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。pa
Stella981 Stella981
3年前
Apache commons chain 初探
Apachecommonschain是什么Apachecommonchain是对责任链设计模式的改造封装,让使用者更加方便的使用。简单回顾一下责任链设计模式在阎宏博士的《JAVA与模式》一书中开头是这样描述责任链(ChainofResponsibility)模式的:责任链模式是一种对象的行为模式。在
Stella981 Stella981
3年前
Redis pipeline(12)
常规的连接客户端一般有3种请求方式:1.Client2.Pipeline3.事务三中模式的区别Client模式:就是客户端发送一个命令,阻塞等待服务端执行,然后读取返回结果。Pipeline模式:是一次性发送多个命令,最后一次取回所有的返回结果,这种模式通过减少网络的往返时间和io读写次数,大幅度提高通信性能。事
Wesley13 Wesley13
3年前
Java设计模式之责任链模式
引入责任链模式责任链模式顾名思义,责任链模式(ChainofResponsibilityPattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会
Wesley13 Wesley13
3年前
00_设计模式之语言选择
设计模式之语言选择设计模式简介背景设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式(Designpattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的
Wesley13 Wesley13
3年前
GEF 命令模式介绍
命令模式的结构如图:在我们流程设计器中,实现复制粘贴功能,就是采用了命令模式,以剪切操作为例,当在编辑器中选中活动,在菜单中选择“剪切”,就会产生一个剪切命令(CutCommand对象)。剪切操作所用到的类如下:名称说明org.eclipse.gef.commands.Command命令的抽象类org.eclipse.gef.co
Wesley13 Wesley13
3年前
23种设计模式(面向对象语言)
一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。创建型模式是用来创建对象的模式,抽象了实例化的过程,帮助一个系统独立于其他关联对象的创建、组合和表示方式。所有的创建型模式都有两个主要功能:  1.将系统所使用的具体类的信息封装起来  2.隐藏
Wesley13 Wesley13
3年前
Java设计模式——命令模式
命令模式命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的。我们看看关系图:!(https://oscim
京东云开发者 京东云开发者
2个月前
还在自己实现责任链?我建议你造轮子之前先看看这个开源项目
1.前言设计模式在软件开发中被广泛使用。通过使用设计模式,开发人员可以更加高效地开发出高质量的软件系统,提高代码的可读性、可维护性和可扩展性。责任链模式是一种常用的行为型设计模式,它将请求沿着处理链进行发送,直到其中一个处理者对请求进行处理为止。在责任链模