返回

命令模式:优雅地组织程序功能,实现代码解耦

闲谈

引言:命令模式的魅力

在软件开发中,我们经常会遇到这样的场景:我们需要将一个请求发送给某个对象,但是我们并不知道这个对象是谁,或者这个对象在执行请求时需要什么参数。此时,命令模式就可以派上用场了。

命令模式是一种数据驱动的设计模式,它属于行为型模式。命令模式将请求封装成对象,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把请求委托给该对象去处理。命令模式可以将请求和执行请求的对象解耦,从而提高程序的灵活性和可扩展性。

命令模式的结构

命令模式主要由以下几个角色组成:

  • 命令(Command) :命令接口,定义了执行请求的方法。
  • 具体命令(Concrete Command) :实现了命令接口的具体类,负责执行具体的请求。
  • 调用者(Invoker) :负责接收命令并将其转发给相应的具体命令对象。
  • 接收者(Receiver) :负责执行具体命令。

命令模式的优点

命令模式具有以下优点:

  • 解耦: 命令模式将请求和执行请求的对象解耦,使得我们可以很容易地修改或替换任何一个组件,而不会影响其他组件。
  • 灵活性: 命令模式可以很容易地添加新的命令,而不需要修改调用者或接收者。
  • 可扩展性: 命令模式可以很容易地扩展,以支持新的请求类型。
  • 重用: 命令模式可以将相同的命令对象用于不同的调用者,从而提高代码的重用性。

命令模式的应用场景

命令模式可以用于以下场景:

  • 当我们需要将一个请求发送给某个对象,但是我们并不知道这个对象是谁,或者这个对象在执行请求时需要什么参数时。
  • 当我们需要将一个请求发送给多个对象时。
  • 当我们需要记录请求的执行历史时。
  • 当我们需要撤销或重做请求时。

命令模式的示例

以下是一个命令模式的示例代码:

public interface Command {
    void execute();
}

public class ConcreteCommandA implements Command {
    private Receiver receiver;

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

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

public class ConcreteCommandB implements Command {
    private Receiver receiver;

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

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

public class Receiver {
    public void actionA() {
        // 执行动作 A
    }

    public void actionB() {
        // 执行动作 B
    }
}

public class Invoker {
    private Command command;

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

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

public class Client {
    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        Command commandA = new ConcreteCommandA(receiver);
        Command commandB = new ConcreteCommandB(receiver);

        Invoker invoker = new Invoker(commandA);
        invoker.invoke();

        invoker = new Invoker(commandB);
        invoker.invoke();
    }
}

在上面的示例代码中,我们定义了一个命令接口 Command,两个具体命令类 ConcreteCommandAConcreteCommandB,一个接收者类 Receiver,一个调用者类 Invoker 和一个客户端类 Client

客户端类 Client 创建了一个接收者对象 receiver,两个具体命令对象 commandAcommandB,以及一个调用者对象 invoker。然后,客户端类 Client 调用调用者对象 invokerinvoke() 方法,将具体命令对象 commandA 传递给调用者对象 invoker。调用者对象 invoker 调用具体命令对象 commandAexecute() 方法,具体命令对象 commandA 调用接收者对象 receiveractionA() 方法。

接下来,客户端类 Client 调用调用者对象 invokerinvoke() 方法,将具体命令对象 commandB 传递给调用者对象 invoker。调用者对象 invoker 调用具体命令对象 commandBexecute() 方法,具体命令对象 commandB 调用接收者对象 receiveractionB() 方法。

输出结果如下:

执行动作 A
执行动作 B