Command模式

设计模式中的Command模式是一种行为设计模式,它将一个请求或简单操作封装成一个对象。这种模式允许用户根据不同的请求、队列或日志请求来参数化其他对象。它也支持可撤销的操作。Command模式的核心在于四种角色:

  1. Command:定义执行操作的接口。
  2. ConcreteCommand:实现Command接口的具体类,它有一个接收者(Receiver)对象并调用接收者的功能来完成命令要执行的操作。
  3. Receiver:执行与请求相关的操作,具体执行命令的组件。
  4. Invoker:请求的发送者,持有Command对象,并在某个时间点调用Command对象的execute方法来提交请求。

使用Command模式可以很容易地将一连串独立的操作通过配置连成Command链或者invocation链,并针对执行结果实现分支,重试或回滚等。这样可以将复杂的系统集成场景解成不同的Command并分配在团队中开发实现,后期可以轻松地添加新的Command,调整配置,而保持最大的代码重用性。而这种模式称为责任链(Chain of Responsibilities)模式。Servlet Filter和Python开源库LangChain是责任链模式的绝佳例子。

Java

假设我们有一个简单的命令,打开电灯(Light On Command)。

Command Interface

public interface Command {
    void execute();
}

ConcreteCommand

public class LightOnCommand implements Command {
    Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    public void execute() {
        light.on();
    }
}

Receiver

public class Light {
    public void on() {
        System.out.println("Light is on");
    }

    public void off() {
        System.out.println("Light is off");
    }
}

Invoker

public class RemoteControl {
    Command slot;

    public RemoteControl() {}

    public void setCommand(Command command) {
        slot = command;
    }

    public void buttonWasPressed() {
        slot.execute();
    }
}

客户端代码

public class RemoteLoader {
    public static void main(String[] args) {
        RemoteControl remote = new RemoteControl();
        Light light = new Light();
        LightOnCommand lightOn = new LightOnCommand(light);

        remote.setCommand(lightOn);
        remote.buttonWasPressed();
    }
}

Golang

Command Interface

package main

import "fmt"

type Command interface {
    Execute()
}

ConcreteCommand

type LightOnCommand struct {
    light *Light
}

func (c *LightOnCommand) Execute() {
    c.light.On()
}

Receiver

type Light struct {}

func (l *Light) On() {
    fmt.Println("Light is on")
}

func (l *Light) Off() {
    fmt.Println("Light is off")
}

Invoker

type RemoteControl struct {
    command Command
}

func (r *RemoteControl) SetCommand(command Command) {
    r.command = command
}

func (r *RemoteControl) PressButton() {
    r.command.Execute()
}

客户端代码

func main() {
    light := &Light{}
    lightOnCommand := &LightOnCommand{light}
    remote := RemoteControl{}
    remote.SetCommand(lightOnCommand)
    remote.PressButton()
}

Python

Command Interface

from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

ConcreteCommand

class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light

    def execute(self):
        self.light.on()

Receiver

class Light:
    def on(self):
        print("Light is on")

    def off(self):
        print("Light is off")

Invoker

class RemoteControl:
    def __init__(self):
        self.command = None

    def set_command(self, command):
        self.command = command

    def press_button(self):
        self.command.execute()

客户端代码

if __name__ == "__main__":
    light = Light()
    light_on = LightOnCommand(light)
    remote = RemoteControl()
    remote.set_command(light_on)
    remote.press_button()