命令模式

命令模式(Command Pattern):将一个请求封装为一个对象,以便使用不同的对象。命令模式解决了应用程序中对象的职责,以及他们之间的通信方式。

适用场景

  • 请求调用者和请求接收者需要解耦,使得调用者和接收者不直接交互

  • 需要抽象出等待执行的行为

优点

  • 降低解耦

  • 容易扩展新命令或者一组新命令

缺点

  • 命令的无限扩展会增加类的数量,提高系统的实现复杂度

下面我们引入一种应用场景。在万物互联智能化的今天,大部分的家居产品都可以使用app来进行控制了。就以家里的智能灯为例。我们可以通过一个app控制家里的多个灯。或者对一个灯,进行反复的开关操作。

Golang Demo

package command

import (
    "fmt"
)

type Command interface {
    execute()
}

type Light struct {
    name string
}

func NewLight(name string) *Light {
    return &Light{name: name}
}

func (l *Light) open() {
    fmt.Println("open light " + l.name)
}
func (l *Light) close() {
    fmt.Println("close light " + l.name)
}

type OpenLightCommand struct {
    light *Light
}

func (o *OpenLightCommand) execute() {
    o.light.open()
}

func NewOpenLightCommand(light *Light) *OpenLightCommand {
    return &OpenLightCommand{light: light}
}

type CloseLightCommand struct {
    light *Light
}

func (c *CloseLightCommand) execute() {
    c.light.close()
}

func NewCloseLightCommand(light *Light) *CloseLightCommand {
    return &CloseLightCommand{light: light}
}

type App struct {
    commandList []Command
}

func NewApp() *App {
    return &App{}
}

func (a *App) addCommand(command Command) {
    a.commandList = append(a.commandList, command)
}

func (a *App) executeCommand() {
    for _, command := range a.commandList {
        command.execute()
    }
    // 清空这个切片
    a.commandList = a.commandList[0:0]
}
package command

func ExampleCommand() {
    light := NewLight("小智同学")
    openLightCommand := NewOpenLightCommand(light)
    closeLightCommand := NewCloseLightCommand(light)
    app := NewApp()
    app.addCommand(openLightCommand)
    app.addCommand(closeLightCommand)
    app.executeCommand()
    //Output:
    //open light 小智同学
    //close light 小智同学
}

Java Demo

首先我们定义一个命令接口。

package tech.selinux.design.pattern.behavioral.command;

public interface Command {
  void execute();
}

创建一款智能灯。

package tech.selinux.design.pattern.behavioral.command;

// 智能灯
// 有个名字 小智同学
public class Light {
  private String name;

  public Light(String name) {
    this.name = name;
  }

  public void open() {
    System.out.println("open light " + this.name);
  }

  public void close() {
    System.out.println("close light" + this.name);
  }
}

设计相应的开灯命令,和关灯命令。

package tech.selinux.design.pattern.behavioral.command;

public class OpenLightCommand implements Command {
  private Light light;

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

  @Override
  public void execute() {
    light.open();
  }
}
package tech.selinux.design.pattern.behavioral.command;

public class CloseLightCommand implements Command {
  private Light light;

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

  @Override
  public void execute() {
    light.close();
  }
}

接下来,我们定义一个app类型的模拟类,这里面可以批量的接收和执行command

package tech.selinux.design.pattern.behavioral.command;

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

public class App {
  private List<Command> commandList = new ArrayList<Command>();

  public void addCommand(Command command) {
    commandList.add(command);
  }

  public void executeCommand() {
    for (Command command : commandList) {
      command.execute();
    }
    commandList.clear();
  }
}
package tech.selinux.design.pattern.behavioral.command;

public class Test {
  public static void main(String[] args) {
    Light light = new Light("小智同学");

    OpenLightCommand openLightCommand = new OpenLightCommand(light);
    CloseLightCommand closeLightCommand = new CloseLightCommand(light);
    App app = new App();
    app.addCommand(openLightCommand);
    app.addCommand(closeLightCommand);
    app.executeCommand();
  }
}

UML

补充另一个版本的Java/Scala Demo 以及源码解析

Java Demo_

Scala Demo

UML_

源码解析

Last updated