命令模式是一种行为型模式。它建议将请求封装为一个独立的对象。在这个对象里包含请求相关的全部信息,因此可以将其独立执行。

在命令模式中有如下基础组件:

  • Receiver:唯一包含业务逻辑的类,命令对象会将请求传递给它,请求的最终处理者
  • Command:组装了一个Receiver成员,并绑定实现了Receiver的一个特定行为
  • Invoker:请求的发送者,组装了Command成员,通过调用Command实例的execute()方法来触发对应的指令
  • Client:通过将Receiver实例传递给Command构造器来创建Command对象,之后会将创建的对象同Invoker绑定。

还是通过一个具体的场景来理解下命令模式是怎样运行的。以打开电视这个行为举例,我们可以通过如下方式打开电视:

  1. 通过遥控器开关打开电视
  2. 通过电视上的开关打开电视

在这个场景中,我们有一个指令(Command)是“打开电视”,指令的接收者(Receiver)当然就是电视(TV)了,当我们执行(execute)指令时,相关指令就会让电视打开(TV.on())。

再明确下这个场景中的所有组件:

  • Receiver是TV
  • Command只有一个,是打开电视:ON,这个指令需要组装TV成员
  • Invoker是遥控打开或开关打开这两种方式,它们会组装ON指令成员。

注意,这里我们将“打开电视”这个请求封装到了一个ON指令对象中,这个指令可以被不同的调用方调用。在ON指令中嵌入了TV实例,可以被独立执行。

再举个例子,想想PhotoShop这个软件,在PhotoShop中,要执行“保存”操作有三种方式:

  1. 从右键菜单中执行保存
  2. 从工具栏菜单中执行保存
  3. 使用Ctrl+S快捷键

这三种操作做的是同一件事情:保存正在编辑的图片。这三种操作的保存行为可以抽象为一个“Save”指令对象,而正在被编辑的图片就可以视为一个Receiver。

现在总结下使用命令对象的好处:

  1. 抽象出了潜藏的真实业务逻辑,并将其和具体的操作解耦
  2. 不需要为每个调用者创建不同的处理器
  3. 指令对象包含了执行所需的全部信息,因此它也适用于需要延迟执行的场景

看下UML类图:

  1. 注意下Invoker是怎样嵌入指令对象的。当一个请求发送给Invoker的时候,Invoker会将这个请求传递给其嵌入的命令对象。
  2. 所有具体的指令类都会组装一个Receiver成员属性。

代码如下:

代码如下:

command.go(指令 interface)

type command interface {
execute()
}

device.go(Receiver interface)

type device interface {
on()
off()
}

tv.go(Receiver)

import "fmt"

type tv struct {
isRunning bool
} func (t *tv) on() {
t.isRunning = true
fmt.Println("Turning tv on")
} func (t *tv) off() {
t.isRunning = false
fmt.Println("Turning tv off")
}

onCommand.go(指令)

type onCommand struct {
device device
} func (c *onCommand) execute() {
c.device.on()
}

offCommand.go(指令)

type offCommand struct {
device device
} func (c *offCommand) execute() {
c.device.off()
}

button.go(Invoker,开关打开电视)

type button struct {
command command
} func (b *button) press() {
b.command.execute()
}

main.go(Client)

func main() {

	tv := &tv{}
onCommand := &onCommand{
device: tv,
} offCommand := &offCommand{
device: tv,
} onButton := &button{
command: onCommand,
} onButton.press() offButton := &button{
command: offCommand,
}
offButton.press()
}

运行结果:

Turning tv on
Turning tv off

代码已上传至GitHub:github / zhyea / command 

END!

GoLang设计模式08 - 命令模式的更多相关文章

  1. 设计模式 ( 十三 ) 命令模式Command(对象行为型)

    设计模式 ( 十三 ) 命令模式Command(对象行为型) 1.概述         在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需 ...

  2. 乐在其中设计模式(C#) - 命令模式(Command Pattern)

    原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...

  3. 面向对象设计模式_命令模式(Command)解读

    在.Net框架中很多对象的方法中都会有Invoke方法,这种方法的设计实际是用了设计模式的命令模式, 模式图如下 其核心思路是将Client 向Receiver发送的命令行为进行抽象(ICommand ...

  4. 折腾Java设计模式之命令模式

    博客原文地址 折腾Java设计模式之命令模式 命令模式 wiki上的描述 Encapsulate a request as an object, thereby allowing for the pa ...

  5. Golang设计模式—简单工厂模式(Simple Factory Pattern)

    Golang设计模式--简单工厂模式 背景 假设我们在做一款小型翻译软件,软件可以将德语.英语.日语都翻译成目标中文,并显示在前端. 思路 我们会有三个具体的语言翻译结构体,或许以后还有更多,但现在分 ...

  6. 用Java 8 Lambda表达式实现设计模式:命令模式

    在这篇博客里,我将说明如何在使用 Java 8 Lambda表达式 的函数式编程方式 时实现 命令 设计模式 .命令模式的目标是将请求封装成一个对象,从对客户端的不同类型请求,例如队列或日志请求参数化 ...

  7. python设计模式之命令模式

    python设计模式之命令模式 现在多数应用都有撤销操作.虽然难以想象,但在很多年里,任何软件中确实都不存在撤销操作.撤销操作是在1974年引入的,但Fortran和Lisp分别早在1957年和195 ...

  8. Head First 设计模式 --6 命令模式

    命令模式:将"请求"封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象.命令模式也支持可撤销的操作.用到的原则:1.封装变化2.组合优于继承3.针对接口编程,不能针对实现 ...

  9. C#设计模式(15)——命令模式(Command Pattern)

    一.前言 之前一直在忙于工作上的事情,关于设计模式系列一直没更新,最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的 ...

随机推荐

  1. Qt foreach关键字用法(无师自通)

    Qt 提供一个关键字 foreach (实际是 <QtGlobal> 里定义的一个宏)用于方便地访问容器里所有数据项. foreach 关键字用于遍历容路中所有的项,使用 foreach ...

  2. 如何在github上传本地项目代码

    首先你要在github上申请一个账号 网址:https://github.com/ 然后你要下载一个git工具 网址:https://gitforwindows.org/ 进入官网直接下载就行,下载完 ...

  3. 【ArcEngine】多用户同时编辑同一个版本数据的解决方法

    ArcMap或ArcEngine中,使用多个用户同时编辑default版本的时候,问题就来了,StopEditing 错误信息如下 FDO_E_VERSION_REDEFINED -214721714 ...

  4. mysql主要的两个索引Innodb和MyIASM。

    参考:https://www.cnblogs.com/xiaohaillong/p/6079551.html 1. a.Innodb引擎,Innodb引擎提供了对数据库ACID事务的支持.并且还提供了 ...

  5. LeetCode入门指南 之 回溯思想

    模板 result = {} void backtrack(选择列表, 路径) { if (满足结束条件) { result.add(路径) return } for 选择 in 选择列表 { 做选择 ...

  6. Java的Class类及static块的执行时机

    要理解RTTI在Java中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工程由Class对象完成,它包含了与类有关的信息.Java使用Class对象来执行其RTTI,即使你执行的是类似转型 ...

  7. Vue 2.0 与 Vue 3.0 响应式原理比较

    Vue 2.0 的响应式是基于Object.defineProperty实现的 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 prop ...

  8. 云原生学习筑基 ~ 组网必备知识点 ~ DNS服务

    @ 目录 一.为啥写这篇文章? 二.DNS的作用 三.域 四.DNS工作原理 五.搭建DNS服务器 5.1.Bind 5.2.系统环境准备 5.3.安装 5.4.查看bind的相关文件 5.5.查看b ...

  9. Linux从头学12:读完这篇【特权级】文章,你就比别人更“精通”操作系统!

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  10. CommonsBeanutils1 分析笔记

    1.PropertyUtils.getProperty commons-beanutils-1.9.2.jar 包下的 PropertyUtils#getProperty方法相对于getXxx方法,取 ...