标准 专业
多元 极客

设计模式实验室(12)——命令模式

什么是命令模式?

命令模式是一种对象行为型模式。

命令模式将请求封装为一个对象,由此将发出命令的责任和执行命令的责任分开,命令发送者向命令对象发送一个命令请求,命令对象接收到命令请求,经过处理,将请求转向给合适的接收者。命令发送者不知道哪个对象去执行命令、何时执行、怎么执行等。

进销存模式其实就是一个命令模式的具体实现。如果生产所需的原材料没有,那么我们可以直接通过发送一个进货的命令,订单系统在根据具体类型进行处理。如果我们的产品已经上市了,那么可以通过调用者发送出货命令,向外销售产品,这就是命令模式。

核心结构

  • Commmand。抽象命令类,一般是一个抽象类或者接口,声明了请求执行的方法。
  • ConcreteCommand。具体命令类,是抽象命令类的子类,实现了抽象明类中声明的请求执行的方法。它绑定了具体的接收者对象,并执行对象的执行方法。
  • Invoker。请求发送者,负责向命令对象发送命令请求,并且不需要感知是否存在已实现的请求接收者。
  • Receiver。请求接收者,负责执行具体的请求。

类图展示

命令模式

代码分析

在模式介绍中,我们讲到了进销存模型,我们就用这个例子实现一下命令模式。

首先,我定义一个抽象命令类——订单管理系统:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 命令模式——抽象命令
 */
public abstract class Order {

    public abstract void execute();
}

由于调用者并不知道调用哪个具体命令,故此时我们可以声明一个调用者:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 命令模式——请求发送
 */
public class Invoker {  

    private List<Order> orderList = new ArrayList<Order>();

    public void addOrder(Order order) {
        orderList.add(order);
    }  

    public void executeOrders() {
        System.out.println("Orders are handling");
        for (Order order : orderList) {
            order.execute();
        }
        System.out.println("Orders have handled");
    }
}

接下来就是具体命令类和具体命令的接收者了,首先是进货的实现:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 命令模式——具体命令
 */
public class ImportOrder extends Order {

    private ImportGoods importGoods;   

    public ImportOrder() {
        this.importGoods = new ImportGoods("macbook 15'", 24000.0);
    }    

    @Override
    public void execute() {
        importGoods.importGoods();
    }
}
/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 命令模式——请求接收
 */
public class ImportGoods {

    private String name;

    private Double price;    

    public ImportGoods(String name, Double price) {
        this.name = name;
        this.price = price;
    }   

    public void importGoods() {
        System.out.println("The commodity's name is ".concat(this.name).concat(" and the price is ").concat(String.valueOf(this.price)));
    }
}

接着就是出货实现:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 命令模式——具体命令
 */
public class ExportOrder extends Order {

    private ExportGoods exportGoods;

    public ExportOrder() {
        this.exportGoods = new ExportGoods("macbook 15'", 30000.0);
    }    

    @Override
    public void execute() {
        exportGoods.exportGoods();
    }
}
/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 命令模式——请求接收
 */
public class ExportGoods {

    private String name;

    private Double price;    

    public ExportGoods(String name, Double price) {
        this.name = name;
        this.price = price;
    }    

    public void exportGoods() {
        System.out.println("The commodity's name is ".concat(this.name).concat(" and the price is ").concat(String.valueOf(this.price)));
    }
}

这样,一个命令模式模型就完成了。

上测试代码:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 命令模式测试
 */
public class CommandTest {

    public static void main(String[] args) {
        commandTest();
    }

    private static void commandTest() {
        try {
            Order importOrder = new ImportOrder();
            Order exportOrder = new ExportOrder();
            Invoker invoker = new Invoker();
            invoker.addOrder(importOrder);
            invoker.addOrder(exportOrder);
            invoker.executeOrders();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

模式总结

优点

  • 降低了系统的耦合度。调用者和接受者完全解耦,调用者不需要知道具体的接收者,接收者也不知道命令来自于哪个调用者。
  • 可以实现撤销和恢复的模型。
  • 扩展命令变得很容易。
  • 结合组合模式可以比较容易的设计出一个命令队列。

缺点

  • 新增命令会导致系统中具体命令类激增。

试用场景

  • 调用者和接收者之间不需要对方的存在。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。
  • 系统需要支持命令的撤销和恢复。
  • 需要命令队列,或者是宏命令。
赞(1) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫