《golang设计模式》第三部分·行为型模式-02-命令模式(Command)

文章目录

  • [1. 概述](#1. 概述)
    • [1.1 角色](#1.1 角色)
    • [1.2 类图](#1.2 类图)
  • [2. 代码示例](#2. 代码示例)
    • [2.1 设计](#2.1 设计)
    • [2.2 代码](#2.2 代码)
    • [2.3 类图](#2.3 类图)

1. 概述

命令模式(Command)将类的业务行为以对象的方式封装,以便实现行为的参数化、撤销或重做等需求。

  • 非命令模式的困惑:
    类的行为在运行时是以实例方法的形式调用的,当方法执行完毕并返回后,方法栈将会消除;方法的运行状态(主要指局部变量)保存在栈帧中,它会随着方法栈的销毁而丢失。当方法的运行状态丢失时,撤销、重做等类似操作就很难顺利实现。
  • 命令模式的优势:
    命令模式将目标类的业务行为分离出去,并用单独的对象类(称为命令类)封装。在程序运行时,被分离的业务行为作为一个独立的对象存在,可以被存储或参数化(作为参数在不同对象间传递),为实现该行为的撤销、重做等提供支持。

1.1 角色

  • Command(抽象命令):一般定义为接口,用来定义执行的命令。
  • ConcreteCommand(具体命令):通常会持有接收者对象,并调用接收者对象的相应功能来完成命令要执行的操作。
  • Receiver(接收者):真正执行命令的对象。任何类都可能成为接收者,只要它能够实现命令要求实现的相应功能。
  • Invoker(调用者):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
  • Client:创建具体的命令对象,并且设置命令对象的接收者。

1.2 类图

<<interface>> Command +execute() ConcreteCommand -state: State -receiver:Receiver +execute() Receiver +CommandAction() Invoker +store() Client +store()

2. 代码示例

2.1 设计

  • 定义一个抽象命令Command
  • 定义两个具体命令StartStop
    • 它实现了抽象命令Command
    • 它继承了接收者Service
  • 定义一个接收者Service
    • 它有Start()Stop()两个方法分别对应它的启动和停止操作
  • 定义一个调用者
    • 它是Command的聚合
    • 它的AddCommand()方法将Command加入调用者
    • 它的Option()方法执行了加入它的命令
  • 调用
    • 实例化一个接收者
    • 实例化两个具体命令
    • 实例化一个执行者,各命令加入执行者
    • 执行执行者的Option()方法
    • 验证接收者状态

2.2 代码

  • 代码
go 复制代码
package main

import "fmt"

// 创建抽象命令
type Command interface {
	execute()
}

// 创建具体命令start
type Start struct {
	Status  bool
	Service *Service
}

func (s *Start) execute() {
	err := s.Service.start()
	if err != nil {
		s.Status = true
	}
	s.Status = false
}

// 定义具体命令Stop
type Stop struct {
	Status  bool
	Service *Service
}

func (s *Stop) execute() {
	err := s.Service.stop()
	if err != nil {
		s.Status = true
	}
	s.Status = false
}

// 定义接收者
type Service struct {
	status string
}

func (s *Service) start() (err error) {
	fmt.Println("执行启动操作") //假装执行了操作,实际操作中如果有错这里会抛出
	s.status = "Running"
	return nil
}

func (s *Service) stop() (err error) {
	fmt.Println("执行停止操作") //假装执行了停止,实际操作中如果有错这里会抛出
	s.status = "Exited"
	return nil
}

func (s *Service) GetStatus() {
	fmt.Printf("服务状态:%+v", s.status)
}

// 调用者
type Invoker struct {
	commands []Command
}

func (i *Invoker) AddCommand(command ...Command) {
	i.commands = append(i.commands, command...)

}

func (i *Invoker) option() {
	for _, command := range i.commands {
		command.execute()
	}
}

func main() {
	//实例化一个接收者
	myService := &Service{}

	//实例化一个具体命令
	start := &Start{
		Service: myService,
	}
	//实例化另一个具体命令
	stop := &Stop{
		Service: myService,
	}
	//实例化一个调用者
	invoker := &Invoker{}
	//将刚才实例化的命令加入调用者
	invoker.AddCommand(stop, start)
	//执行操作
	invoker.option()

	//验证接受者状态
	myService.GetStatus()
}
  • 输出
shell 复制代码
执行停止操作
执行启动操作     
服务状态:Running

2.3 类图

Invoker +commands:[]Command +AddCommand(command ...Command) option() <<interface>> Command +execute() Start +Status:bool +Service:*Service +Execute() Stop +Status:bool +Service:*Service +Execute() Service +status:string +start() error) +stop()error) +GetStatus()

相关推荐
黄林晴6 小时前
Android17引入DeliQueue新架构: 为什么要重写MessageQueue?
架构
学嵌入式的小杨同学6 小时前
STM32 进阶封神之路(三十二):SPI 通信深度实战 —— 硬件 SPI 驱动 W25Q64 闪存(底层时序 + 寄存器配置 + 读写封装)
c++·stm32·单片机·嵌入式硬件·mcu·架构·硬件架构
RestCloud7 小时前
API网关 vs iPaaS:企业集成架构选型的本质差异与2026年选型指南
架构·数据处理·数据传输·ipaas·ai网关·集成平台
tobias.b8 小时前
软件设计模式:核心术语·名词解释·关联对比
设计模式
人间打气筒(Ada)8 小时前
go实战案例:如何通过 Service Meh 实现熔断和限流
java·开发语言·golang·web·istio·service mesh·熔断限流
weixin_4491904110 小时前
defer和defer func执行区别
golang
TechWayfarer10 小时前
高并发场景下的IP归属地查询架构:从20ms到0.5ms的优化实践
网络协议·tcp/ip·架构
薛定谔的悦10 小时前
站控显示下级从控EMS的版本信息开发
架构
AI枫林晚10 小时前
源码解析Claude Code 项目 queryLoop 运行机制分析
人工智能·架构
呆萌很11 小时前
【GO】指针练习题
golang