命令模式是一种数据驱动型的模式。
在命令模式中,我们可以将请求以命令的形式包裹在对象中,然后将该对象委托给接受者,接受者在获取到这些命令对象后,在合适的时机去执行这些对象里的命令。

示例

假设我们是股票持有人,现在想要买卖一些股票。一般情况下,我们会将买卖的行为委托给经纪人去执行。也就是说,我们传达买卖股票的命令给经纪人,在开盘后经纪人就会去执行这些命令。
想买股票?首先你要有一个股票类:

  1. public class Stock {
  2. private String name;
  3. private int quantity;
  4. public Stock(String name, int quantity) {
  5. this.name = name;
  6. this.quantity = quantity;
  7. }
  8. // getter and setter ...

想下命令?你得抽象出命令的接口,然后再实现买卖命令的具体类:

  1. // 命令接口
  2. public interface Order {
  3. void execute();
  4. }
  5. // 购买股票的具体命令类
  6. public class BuyOrder implements Order {
  7. private Stock mStock;
  8. public BuyOrder(Stock stock) {
  9. mStock = stock;
  10. }
  11. @Override
  12. public void execute() {
  13. System.out.println("Buy stock: name = " + mStock.getName()
  14. + ", quantity = " + mStock.getQuantity());
  15. }
  16. }
  17. // 卖出股票的具体命令类
  18. public class SellOrder implements Order {
  19. private Stock mStock;
  20. public SellOrder(Stock stock) {
  21. mStock = stock;
  22. }
  23. @Override
  24. public void execute() {
  25. System.out.println("Sell stock: name = " + mStock.getName()
  26. + ", quantity = " + mStock.getQuantity());
  27. }
  28. }

没有经济人?你得构造一个:

  1. public class Broker {
  2. // 买卖股票的命令
  3. private List<Order> mOrders;
  4. public Broker() {
  5. mOrders = new ArrayList<>();
  6. }
  7. // 接收命令
  8. public void takeOrder(Order order) {
  9. mOrders.add(order);
  10. }
  11. // 执行命令
  12. public void placeOrders() {
  13. for(Order order : mOrders) {
  14. order.execute();
  15. }
  16. mOrders.clear();
  17. }
  18. }

好,铛铛铛… 开盘了!

  1. // 喂,哥们儿 (经纪人),在开盘后你就帮我买进 ABC 股 100 份
  2. // 然后在行情好时帮我卖掉 80 份,就酱,谢谢
  3. public static void main(String[] args) {
  4. Stock stock1 = new Stock("ABC", 100);
  5. BuyOrder buyOrder = new BuyOrder(stock1);
  6. Stock stock2 = new Stock("ABC", 80);
  7. SellOrder sellOrder = new SellOrder(stock2);
  8. Broker broker = new Broker();
  9. broker.takeOrder(buyOrder);
  10. broker.takeOrder(sellOrder);
  11. broker.placeOrders();
  12. }

经纪人在开盘后的行为如下:

  1. Buy stock: name = ABC, quantity = 100
  2. Sell stock: name = ABC, quantity = 80

嗯,这就是我们要演示的「命令模式」栗子,下面是示意图:
image.png
怎么后面多了个「撤销卖出股票行为」的命令?因为股票是种神奇的东西呀,持有人在经纪人卖出 80 份股票后预期 ABC 还会继续涨,于是火急火燎地又给经纪人哥们打了个电话。

总结

关于命令模式

  • 意图:将不同的请求封装成不同的命令对象,然后委托给命令接收者去执行。
  • 命令:委托方 -> 接收者 -> 执行。
  • 使用场景:在某些场景下,可能需要对行为进行「记录」、「撤销」/「重做」、「事务」等处理,如果通过常规的、无法抵御变化的、紧耦合的方式去实现是不合适的。在这些场景下,应该将这些行为抽象成对象,将「行为委托方」与「行为接收和执行方」进行松耦合。
  • 优点:逻辑清晰,降低了系统耦合度,新的命令可以很容易地添加到系统中。
  • 缺点:每增加一种命令时,都需要实现一个具体命令类,在一定程度上也增加了系统复杂度。