什么是命令模式?
命令模式是一种对象行为型模式。
命令模式将请求封装为一个对象,由此将发出命令的责任和执行命令的责任分开,命令发送者向命令对象发送一个命令请求,命令对象接收到命令请求,经过处理,将请求转向给合适的接收者。命令发送者不知道哪个对象去执行命令、何时执行、怎么执行等。
进销存模式其实就是一个命令模式的具体实现。如果生产所需的原材料没有,那么我们可以直接通过发送一个进货的命令,订单系统在根据具体类型进行处理。如果我们的产品已经上市了,那么可以通过调用者发送出货命令,向外销售产品,这就是命令模式。
核心结构
- 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();
}
}
}
模式总结
优点
- 降低了系统的耦合度。调用者和接受者完全解耦,调用者不需要知道具体的接收者,接收者也不知道命令来自于哪个调用者。
- 可以实现撤销和恢复的模型。
- 扩展命令变得很容易。
- 结合组合模式可以比较容易的设计出一个命令队列。
缺点
- 新增命令会导致系统中具体命令类激增。
试用场景
- 调用者和接收者之间不需要对方的存在。
- 系统需要在不同的时间指定请求、将请求排队和执行请求。
- 系统需要支持命令的撤销和恢复。
- 需要命令队列,或者是宏命令。