通俗易懂设计模式(命令模式)

75 阅读6分钟

命令模式(Command Pattern)是一种行为型设计模式,它将一个请求封装为一个对象,从而使得请求可以被传递、存储、撤销和重做。命令模式的主要目的是将请求的发送者和接收者解耦,让多个请求的发送者可以通过相同的接口来发送请求,而不需要知道请求的具体实现。

命令模式的主要组成部分包括:

  1. 命令(Command):定义了一个接口,用于执行请求。命令可以是一个抽象类或者一个接口。
  2. 具体命令(ConcreteCommand):实现了命令接口,并在其中定义了一个指向接收者的引用。具体命令负责将请求传递给接收者,并调用接收者的方法来执行请求。
  3. 接收者(Receiver):负责实际执行请求的对象。接收者可以是任何类,只要它能够实现请求的功能。
  4. 请求者(Invoker):负责发送请求的对象。请求者可以是任何类,只要它能够调用命令的 execute() 方法来发送请求。
  5. 客户端(Client):负责创建命令对象、接收者对象和请求者对象,并将它们组合在一起。客户端可以是任何类,只要它能够创建和组合这些对象。

优点:

  1. 降低了系统的耦合度:命令模式将请求发送者和接收者解耦,使得它们可以独立变化。
  2. 提高了系统的灵活性:命令模式可以动态地创建和组合命令对象,使得系统更加灵活。
  3. 方便实现撤销和重做功能:命令模式可以将请求历史记录下来,从而实现撤销和重做功能。

缺点:

  1. 可能会导致命令类的数量过多:每个具体操作都需要一个命令类,可能会导致命令类的数量过多。
  2. 命令模式可能会导致代码结构变得复杂:命令模式需要引入许多新的类和接口,可能会导致代码结构变得复杂。

Java 实现命令模式的示例代码:

// 命令接口
public interface Command {
    void execute();
    void undo();
}

// 具体命令类
public class ConcreteCommand implements Command {
    private Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.action();
    }

    @Override
    public void undo() {
        receiver.undoAction();
    }
}

// 接收者类
public class Receiver {
    public void action() {
        System.out.println("Receiver: perform action");
    }

    public void undoAction() {
        System.out.println("Receiver: undo action");
    }
}

// 请求者类
public class Invoker {
    private Command command;

    public Invoker(Command command) {
        this.command = command;
    }

    public void setCommand(Command command) {
        this.command = command;
    }

    public void executeCommand() {
        command.execute();
    }

    public void undoCommand() {
        command.undo();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(receiver);
        Invoker invoker = new Invoker(command);

        invoker.executeCommand();
        invoker.undoCommand();
    }
}

在这个示例中,我们定义了一个命令接口 Command,它包含了 execute()undo() 方法。接着,我们定义了一个具体命令类 ConcreteCommand,它实现了 Command 接口,并在其中定义了一个指向接收者的引用。在具体命令类的 execute()undo() 方法中,我们调用了接收者的相应方法来执行请求。

接着,我们定义了一个接收者类 Receiver,它负责实际执行请求的功能。然后,我们定义了一个请求者类 Invoker,它负责发送请求的对象。在请求者类的 executeCommand()undoCommand() 方法中,我们调用了命令的相应方法来发送请求。

在客户端代码中,我们创建了一个接收者对象、一个命令对象和一个请求者对象,并将它们组合在一起。然后,我们通过请求者对象来发送请求。通过这种方式,我们将请求的发送者和接收者解耦,让多个请求的发送者可以通过相同的接口来发送请求,而不需要知道请求的具体实现。这样,我们就将请求的发送和执行过程封装在了命令类和接收者类中,使得请求的发送和执行变得更加灵活和可扩展。

使用场景:

场景一:订单场景

在订单场景中,我们可以使用命令模式来处理订单的创建、修改和取消操作。

订单实体类:

class Order {
    private String id;
    private String status;

    public Order(String id) {
        this.id = id;
        this.status = "新建";
    }

    public String getId() {
        return id;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}

命令接口:

interface OrderCommand {
    void execute();
    void undo();
}

具体命令类:

class CreateOrderCommand implements OrderCommand {
    private Order order;

    public CreateOrderCommand(Order order) {
        this.order = order;
    }

    @Override
    public void execute() {
        order.setStatus("已创建");
    }

    @Override
    public void undo() {
        order.setStatus("新建");
    }
}

class UpdateOrderCommand implements OrderCommand {
    private Order order;

    public UpdateOrderCommand(Order order) {
        this.order = order;
    }

    @Override
    public void execute() {
        order.setStatus("已修改");
    }

    @Override
    public void undo() {
        order.setStatus("已创建");
    }
}

class CancelOrderCommand implements OrderCommand {
    private Order order;

    public CancelOrderCommand(Order order) {
        this.order = order;
    }

    @Override
    public void execute() {
        order.setStatus("已取消");
    }

    @Override
    public void undo() {
        order.setStatus("已修改");
    }
}

请求发送者类:

class OrderInvoker {
    private OrderCommand command;

    public OrderInvoker(OrderCommand command) {
        this.command = command;
    }

    public void setCommand(OrderCommand command) {
        this.command = command;
    }

    public void executeCommand() {
        command.execute();
    }

    public void undoCommand() {
        command.undo();
    }
}

客户端:

public class Client {
    public static void main(String[] args) {
        Order order = new Order("001");
        OrderCommand createOrderCommand = new CreateOrderCommand(order);
        OrderCommand updateOrderCommand = new UpdateOrderCommand(order);
        OrderCommand cancelOrderCommand = new CancelOrderCommand(order);

        OrderInvoker invoker = new OrderInvoker(createOrderCommand);
        invoker.executeCommand();
        System.out.println("订单状态:" + order.getStatus());

        invoker.setCommand(updateOrderCommand);
        invoker.executeCommand();
        System.out.println("订单状态:" + order.getStatus());

        invoker.setCommand(cancelOrderCommand);
        invoker.executeCommand();
        System.out.println("订单状态:" + order.getStatus());

        invoker.undoCommand();
        System.out.println("订单状态:" + order.getStatus());
    }
}

在这个例子中,我们定义了一个订单实体类Order,以及三个具体的命令类CreateOrderCommandUpdateOrderCommandCancelOrderCommand,分别用于处理订单的创建、修改和取消操作。客户端创建了一个订单对象,并创建了相应的命令对象,然后将命令对象设置到请求发送者OrderInvoker中,通过调用executeCommandundoCommand方法来执行和撤销命令。

场景二:库存场景

库存实体类:

// 库存实体类
class Inventory {
    private String id; // 库存ID
    private int quantity; // 库存数量

    // 构造函数
    public Inventory(String id) {
        this.id = id;
        this.quantity = 0;
    }

    // 获取库存ID
    public String getId() {
        return id;
    }

    // 获取库存数量
    public int getQuantity() {
        return quantity;
    }

    // 设置库存数量
    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
}

命令接口:

// 命令接口
interface InventoryCommand {
    void execute(); // 执行命令
    void undo(); // 撤销命令
}

具体命令类:

// 增加库存命令
class AddInventoryCommand implements InventoryCommand {
    private Inventory inventory; // 库存对象
    private int quantity; // 增加的库存数量

    // 构造函数
    public AddInventoryCommand(Inventory inventory, int quantity) {
        this.inventory = inventory;
        this.quantity = quantity;
    }

    // 执行命令:增加库存数量
    @Override
    public void execute() {
        inventory.setQuantity(inventory.getQuantity() + quantity);
    }

    // 撤销命令:减少库存数量
    @Override
    public void undo() {
        inventory.setQuantity(inventory.getQuantity() - quantity);
    }
}

// 减少库存命令
class RemoveInventoryCommand implements InventoryCommand {
    private Inventory inventory; // 库存对象
    private int quantity; // 减少的库存数量

    // 构造函数
    public RemoveInventoryCommand(Inventory inventory, int quantity) {
        this.inventory = inventory;
        this.quantity = quantity;
    }

    // 执行命令:减少库存数量
    @Override
    public void execute() {
        inventory.setQuantity(inventory.getQuantity() - quantity);
    }

    // 撤销命令:增加库存数量
    @Override
    public void undo() {
        inventory.setQuantity(inventory.getQuantity() + quantity);
    }
}

请求发送者类:

// 请求发送者类
class InventoryInvoker {
    private InventoryCommand command; // 命令对象

    // 构造函数
    public InventoryInvoker(InventoryCommand command) {
        this.command = command;
    }

    // 设置命令对象
    public void setCommand(InventoryCommand command) {
        this.command = command;
    }

    // 执行命令
    public void executeCommand() {
        command.execute();
    }

    // 撤销命令
    public void undoCommand() {
        command.undo();
    }
}

客户端:

public class Client {
    public static void main(String[] args) {
        Inventory inventory = new Inventory("001"); // 创建库存对象
        InventoryCommand addInventoryCommand = new AddInventoryCommand(inventory, 10); // 创建增加库存命令
        InventoryCommand removeInventoryCommand = new RemoveInventoryCommand(inventory, 5); // 创建减少库存命令

        InventoryInvoker invoker = new InventoryInvoker(addInventoryCommand); // 创建请求发送者对象并设置命令
        invoker.executeCommand(); // 执行命令:增加库存
        System.out.println("库存数量:" + inventory.getQuantity()); // 输出库存数量

        invoker.setCommand(removeInventoryCommand); // 设置减少库存命令
        invoker.executeCommand(); // 执行命令:减少库存
        System.out.println("库存数量:" + inventory.getQuantity()); // 输出库存数量

        invoker.undoCommand(); // 撤销命令:增加库存
        System.out.println("库存数量:" + inventory.getQuantity()); // 输出库存数量
    }
}

在这个例子中,我们定义了一个库存实体类Inventory,以及两个具体的命令类AddInventoryCommandRemoveInventoryCommand,分别用于处理库存的增加和减少操作。客户端创建了一个库存对象,并创建了相应的命令对象,然后将命令对象设置到请求发送者InventoryInvoker中,通过调用executeCommandundoCommand方法来执行和撤销命令。