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

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

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

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

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

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

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

  • ReceiverTV
  • 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. SpringBoot使用@Scheduled创建定时任务

    定时任务一般会存在中大型企业级项目中,为了减少服务器.数据库的压力往往会采用时间段性的去完成某些业务逻辑.比较常见的就是金融服务系统推送回调,一般支付系统订单在没有收到成功的回调返回内容时会持续性的回 ...

  2. Executor执行器

    Executors: CachedThreadPool  将为每个任务创建一个线程. public class CachedThreadPool { public static void main(S ...

  3. py2neo学习记录

    py2neo 通用 # -*- coding: UTF-8 -*- from py2neo import Graph, Node, Relationship, walk, NodeMatcher, R ...

  4. go语言 切片表达式

    切片表达式 切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片. 切片表达式中的low和high表示一个索引范围(左包含,右不包含),得到的切片长度=high-low,容量等于得到的切 ...

  5. 修改Windows7系统默认软件安装目录

    Windows7系统默认软件安装目录都在C盘Program Files文件夹有时候我们需要把软件安装到其他地方,如果每次安装的时候都要重新选择一次十分麻烦,下面Windows7之家教你修改软件默认安装 ...

  6. Python3-sqlalchemy-orm 创建多表关联表带外键

    #-*-coding:utf-8-*- #__author__ = "logan.xu" import sqlalchemy from sqlalchemy import crea ...

  7. Android系统编程入门系列之应用内键值对数据的简单保存

    在应用程序间及与用户的通信交互过程中,会产生并传递一系列数据.针对这些数据,有部分是只在应用程序中使用的缓存数据,还有一部分是在不同位置多次或长时间使用的持久化数据. 对于缓存数据来说,通常以代码中定 ...

  8. MyBatis学习总结(三)——MyBatis配置文件配置的优化

    一.连接数据库的配置单独放在一个properties文件中 上文 连接数据库的配置写在 mybatisConf.xml中,本文直接放在 db.properties 中, 在mybatisConf.xm ...

  9. 多Host情况下IDEA无法启动Tomcat的问题

    学习Java Web,学到将WAR包部署到Tomcat中时,遇到一个问题. 部署WAR包的过程本身没什么问题,把.war文件放在<Tomcat安装目录>/webapps/中,然后修改< ...

  10. Emit优化反射(属性的设置与获取)

    在频繁的通过反射来设置和获取属性的值时是比较耗时的,本章通过Emit技术优化反射来提高获取和设置属性值的效率 一.实现代码: /// <summary> /// 设置器委托 /// < ...