设计模式之命令模式

2024-02-04 19:05:30 浏览数 (1)

1. 基本概念

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而允许使用不同的请求、队列或日志请求等方式来参数化其他对象。命令模式也支持可撤销的操作。

在命令模式中,有几个不同的角色,每个角色都有不同的职责和行为。以下是命令模式中的主要角色:

  1. Command(命令接口)
    • 职责: 定义命令的接口,声明执行操作的方法 Execute
    • 行为: 具体的命令类实现该接口,并负责实际执行操作。
  2. ConcreteCommand(具体命令)
    • 职责: 实现 Command接口,将请求绑定到一个接收者对象,并定义了执行请求的操作。
    • 行为: 通常包含对接收者的引用,通过调用接收者的方法来执行具体的操作。
  3. Invoker(调用者)
    • 职责: 负责请求的发送者,即客户端与命令对象之间的中介。
    • 行为: 将命令对象存储在内部,并在需要的时候调用命令的 Execute方法。
  4. Receiver(接收者)
    • 职责: 知道如何实施与请求相关的操作,它具体执行命令指定的操作。
    • 行为: 实际执行操作的对象,是命令所作用的对象。
  5. Client(客户端)
    • 职责: 创建命令对象和设置其接收者,与调用者对象关联。
    • 行为: 创建具体的命令对象,并将其与相应的接收者关联,构建命令的执行链。

在一个典型的命令模式中,这些角色协同工作,通过将请求发送者和接收者解耦,使得系统更具灵活性和可扩展性。调用者不需要知道具体的命令执行细节,而是通过调用命令对象的Execute方法来触发相应的操作。这样,可以轻松地添加新的命令和接收者,而无需修改现有的客户端代码。

2. 适用场景

  • 当需要将请求发送者与接收者解耦时,使用命令模式将请求封装成一个对象。
  • 当需要支持可撤销的操作时,可以使用命令模式来保存操作历史。
  • 当需要支持事务性操作时,可以使用命令模式来将一系列操作组合成一个命令对象。

3. 优缺点

优点:

  • 解耦发送者和接收者: 命令模式将请求发送者和接收者解耦,发送者不需要知道接收者的具体实现。
  • 可扩展性: 可以很容易地添加新的命令类和接收者类,无需修改现有代码。
  • 可撤销的操作: 命令模式支持可撤销的操作,通过保存历史命令可以实现撤销和重做功能。

缺点:

  • 类数目增加: 可能会导致系统中类的数量增加,每个命令都需要一个具体的类。
  • 复杂性增加: 对于简单的命令,可能引入过多的复杂性。

4. 示例

考虑一个简单的遥控器的例子,其中包含一组不同的命令按钮。每个按钮都可以执行不同的操作,例如打开电灯、关闭电灯等。使用命令模式,可以将每个操作封装成一个命令对象。

代码语言:go复制
package main

import "fmt"

// Command Interface
type Command interface {
	Execute()
}

// Receiver
type Light struct{}

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

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

// ConcreteCommand
type TurnOnCommand struct {
	light *Light
}

func NewTurnOnCommand(light *Light) *TurnOnCommand {
	return &TurnOnCommand{light: light}
}

func (c *TurnOnCommand) Execute() {
	c.light.TurnOn()
}

// ConcreteCommand
type TurnOffCommand struct {
	light *Light
}

func NewTurnOffCommand(light *Light) *TurnOffCommand {
	return &TurnOffCommand{light: light}
}

func (c *TurnOffCommand) Execute() {
	c.light.TurnOff()
}

// Invoker
type RemoteControl struct {
	command Command
}

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

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

// Client
func main() {
	light := &Light{}

	turnOnCommand := NewTurnOnCommand(light)
	turnOffCommand := NewTurnOffCommand(light)

	remote := &RemoteControl{}

	remote.SetCommand(turnOnCommand)
	remote.PressButton()

	remote.SetCommand(turnOffCommand)
	remote.PressButton()
}

在这个示例中,Command是命令接口,TurnOnCommandTurnOffCommand是具体的命令类,Light是接收者类,而RemoteControl是调用者类。通过将命令封装成对象,可以轻松地添加新的命令和接收者类,实现了请求发送者和接收者的解耦。

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!


声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。

blog: mengbin

Github: mengbin92

cnblogs: 恋水无意

腾讯云开发者社区:孟斯特


0 人点赞