设计模式:命令模式

1,258 阅读2分钟

是什么?

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

为什么用他?

在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。

一、角色

  1. received 真正的命令执行对象
  2. Command 抽象命令类
  3. invoker 使用命令对象的入口
  4. client 客户端
  5. concreteCommand 具体实现命令类

二、命令模式如何实现解耦?

Invoker同样是针对接口编程,不过这个接口并不是由Receiver实现,而是由命令对象实现。Invoker只管调用命令对象的execute方法即可,它根本不知道execute方法里发生了什么。命令对象就是Invoker和Receiver之间沟通的桥梁。利用命令对象,我们可以根据需要使Invoker调用某个类的某个方法等。

三、代码


package com.godliang.design.command;

import com.sun.org.apache.xpath.internal.operations.Or;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * @author GodLiang
 * @version 1.0
 * @date 2021/2/9 19:34
 * @description: TODO 命令模式
 */
public class CommandPatternDemo {
    public static void main(String[] args) {
        //创建请求类股票
        Stock abcStock = new Stock();

        //创建命令购买股票
        BuyStock buyStockOrder = new BuyStock(abcStock);
        //创建命令卖出股票
        SellStock sellStockOrder = new SellStock(abcStock);

        //执行器
        Broker broker = new Broker();
        //添加命令执行器
        broker.takeOrder(buyStockOrder);
        broker.takeOrder(sellStockOrder);

        //批量执行
        broker.placeOrders();
        broker.undoOrders();
    }
}

/**
 * 请求类
 */
class Stock {

    private String name = "ABC";
    private int quantity = 10;

    public void buy(){
        System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] bought");
    }
    public void sell(){
        System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] sold");
    }
}

/**
 * 命令接口
 */
interface Order {
    /**
     * 执行命令
     */
    void execute();

    /**
     * 撤回
     */
    void undo();
}

/**
 * 实体命令类
 * 购买股票
 */
class BuyStock implements Order {
    private Stock abcStock;

    public BuyStock(Stock abcStock){
        this.abcStock = abcStock;
    }

    @Override
    public void execute() {
        abcStock.buy();
    }

    @Override
    public void undo() {
        abcStock.sell();
    }
}

/**
 * 实体命令类
 * 卖出股票
 */
class SellStock implements Order {
    private Stock abcStock;

    public SellStock(Stock abcStock){
        this.abcStock = abcStock;
    }

    @Override
    public void execute() {
        abcStock.sell();
    }

    @Override
    public void undo() {
        abcStock.buy();
    }
}

/**
 * 命令执行类
 */
class Broker {
    /**
     * 执行集合
     */
    private List<Order> orderList = new ArrayList<Order>();

    /**
     * 撤回按先进后出的方式撤回
     * @param order
     */
    private Stack<Order> orderStack = new Stack<>();
    public void takeOrder(Order order){
        orderList.add(order);
    }

    public void placeOrders(){
        for (Order order : orderList) {
            order.execute();
            //执行完后入栈
            orderStack.add(order);
        }
    }

    /**
     * 撤回
     */
    public void undoOrders(){
        do {
            Order order = orderStack.pop();
            order.undo();
        }while (!orderStack.empty());

    }
}

四、优缺点

优点:

  1. 降低了系统耦合度。
  2. 新的命令可以很容易添加到系统中去。
  3. 可以比较容易的设置组合一套命令
  4. 可以对命令的撤销或重置

缺点:

  1. 由于每个小的命令都要重新实现一个命令实现类。会导致类过多。会影响阅读与使用