设计模式-命令模式(Go语言描述)

标签: 设计模式 go语言
5661人阅读 评论(2) 收藏 举报
分类:

在上一篇博客设计模式-单例模式(Go语言描述)中我们介绍了在golang中如何去实现单例模式,在文章的最后我们也介绍到了golang独有的一种实现单例的方式-sync.Once.Do(),可以让golang轻松的实现可以应对并发请求的单利.今天我们继续探索设计模式,来介绍一下命令模式的实现.

说起命令,大家第一反应可能就是我们平时敲的各种命令,啪啪啪几行命令下去就可以完成一些功能,在看到命令模式这个词后,可能大家也会和我一样认为这里的命令就是执行一些简单任务的功能,然而并不是,这里的命令更多的像是我们发出的请求或者电视遥控器的按键.这样吧,咱们先来看看命令模式的定义,然后再从生活中找实际的例子对比一下.

命令模式是将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作.命令模式是一种对象行为型模式,其别名为动作模式或事务模式.

在命令模式中有如下几个角色:
Command: 命令
Invoker: 调用者
Receiver: 接受者
Client: 客户端

他们的关系可以这么来描述:

客户端通过调用者发送命令,命令调用接收者执行相应操作.

其实命令模式也很简单,不过不知道大家发现没有,在上述描述中调用者和接收者并不知道对方的存在,也就是说他们之间是解耦合的.

还是用遥控器的例子来解释一下吧,遥控器对应上面的角色就是调用者,电视就是接收者,命令呢?对应的就是遥控器上的按键,最后客户端就是我们人啦,当我们想打开电视的时候,就会通过遥控器(调用者)的电源按钮(命令)来打开电视(接收者),在这个过程中遥控器是不知道电视的,但是电源按钮是知道他要控制谁的什么操作.

… 哎呀, 语文不太好,突然发现越描述越不容易让人理解了呢? 还是用代码来实现一下上面遥控器的例子吧.我们对照着上面的角色一个个的去实现.
接收者,也就是一台大大的电视,

// receiver
type TV struct{}

func (p TV) Open() {
    fmt.Println("play...")
}

func (p TV) Close() {
    fmt.Println("stop...")
}

这台电视弱爆了,只有打开和关闭两个功能,对应的就是上面代码中的OpenClose两个方法,虽然很简单,不过我们确实造出了一台电视(估计还是彩色的).
下面,我们再来实现命令,也就是遥控器上的按键,因为电视只有打开和关闭功能,所以按键我们也只提供两个,多了用不上.

// command
type Command interface {
    Press()
}

type OpenCommand struct {
    tv TV
}

func (p OpenCommand) Press() {
    p.tv.Open()
}

type CloseCommand struct {
    tv TV
}

func (p CloseCommand) Press() {
    p.tv.Close()
}

首先我们定义了一个命令接口,只有一个方法就是Press,当我们按下按键时会去调用这个方法,然后我们果然只实现了两个按键,分别是OpenCommandCloseCommand,这两个实现中都保存着一台电视的句柄,并且在Press方法中根据功能去调用了这个tv的相应方法来完成正确的操作.

还有什么我们没有实现? 调用者,也就是遥控器了,来看看遥控器怎么实现吧.

// sender
type Invoker struct {
    cmd Command
}

func (p *Invoker) SetCommand(cmd Command) {
    p.cmd = cmd
}

func (p Invoker) Do() {
    p.cmd.Press()
}

在遥控器中我们有一个Command类型的变量,并且提供了SetCommand方法来设置命令,那我们按下遥控器上的键对应哪个方法呢?看看Do方法,我们直接调用了命令的Press方法,这个时候客户端(就是我们人)拿起遥控器,瞅准了打开按钮(SetCommand),并且按钮该键(Do),按键被按下(Press),电视打开了(Open).

那么最后,来看看客户端怎么去调用吧,

func main() {
    var tv TV
    openCommand := OpenCommand{tv}
    invoker := Invoker{openCommand}
    invoker.Do()

    invoker.SetCommand(CloseCommand{tv})
    invoker.Do()
}

命令模式实现起来也很简单,它降低了我们这个系统的耦合度,并且我们还可以任意拓展命令使用而不需要修改代码,开闭原则体现的淋漓尽致.

现在大家应该对命令模式有了一个直观的认识吧, 不过大家有没有发现一个问题,我们的遥控器在使用某个命令的时候只有set后才能用,也就是说每次只能使用一个命令,那有没有更好的办法来预装命令呢?肯定是有的,这就是我们接下来要介绍的复合命令,也叫做宏命令,复合命令其实说白了就是将多个命令保存起来,通过遍历这个集合来分别调用各个命令.

func NewOpenCloseCommand() *OpenCloseCommand {
    var openClose *OpenCloseCommand = &OpenCloseCommand{}
    openClose.cmds = make([]Command, 2)
    return openClose
}

type OpenCloseCommand struct {
    index int
    cmds  []Command
}

func (p *OpenCloseCommand) AddCommand(cmd Command) {
    p.cmds[p.index] = cmd
    p.index++
}

func (p OpenCloseCommand) Press() {
    for _, item := range p.cmds {
        item.Press()
    }
}

func main() {
  var openClose *OpenCloseCommand = NewOpenCloseCommand()
  openClose.AddCommand(OpenCommand{tv})
  openClose.AddCommand(CloseCommand{tv})
  invoker.SetCommand(openClose)
  invoker.Do()
}

我们定义了一个OpenCloseCommand,这里面用一个切片来保存各个命令,并通过AddCommand方法来王里面添加命令,OpenCloseCommand实现了Press方法,所以本质上他也是一个命令,我们调用他的Press方法来遍历保存的Command,并调用每一个的Press方法.

到这里,命令模式我们就介绍完了,命令模式具有很高的扩展性,遵循了开闭原则,所以减少了修改代码引入bug的可能性,快来想一想你的代码中哪些地方可以用命令模式来解决吧.

查看评论

从C/S到Intranet

从C/S到Intranet(本文转载自软件工程专家网www.21cmm.com) 一、C/S昨天黄花  PC时代到来后,计算机网络和计算机应用得到了很大的发展。PC价格的不断下降和性能的持续上升,逐步...
  • gigix
  • gigix
  • 2002-04-09 09:41:00
  • 1868

设计模式-单例模式(Go语言描述)

这篇博客我们继续来看设计模式,今天带来的是一个最简单而且最常用的模式-单例模式。那什么是单例模式呢?相信大家最它最熟悉不过了,那我们就来快速的了解一下它的定义。 保证一个类仅有一个实例,并提供一个...
  • qibin0506
  • qibin0506
  • 2016-02-24 20:30:18
  • 13030

设计模式-策略模式(Go语言描述)

好久没有更新博客了,最近也是在忙着充电,从今天这篇博客开始,我们来了解一下设计模式。设计模式那什么是设计模式呢?首先来看看我从百科上copy下来的概念吧。 设计模式/软件设计模式(Design p...
  • qibin0506
  • qibin0506
  • 2016-01-22 23:49:23
  • 6736

超赞的GO语言设计模式和成例集锦

来自:http://geek.csdn.net/news/detail/100051 Go语言从面世就受到了业界的普遍关注,曾有文章分析,Go是最有可能改变未来IT技术的十大语言之一。本文作...
  • Blues1021
  • Blues1021
  • 2016-09-08 09:26:09
  • 1187

设计模式 —— 命令模式(Command Pattern)

命令模式(Command Pattern)概念: 概述:在软件设计中,我们经常会遇到某些对象发送请求,然后某些对象接受请求后执行,但发送请求的对象可能并不知道接受请求的对象是谁,执行的是什么动作。...
  • wwh578867817
  • wwh578867817
  • 2016-05-29 18:34:53
  • 2602

go语言实现设计模式(二):简易工厂

简易工厂主要是用来解决对象“创建”的问题。以下的例子取自《大话设计模式》中第一章,实现一个可扩展的“计算器”。当增加新的功能时,并不需改动原来已经实现的算法。由于是简易工厂,所以我们还是需要对工厂类进...
  • yzh900927
  • yzh900927
  • 2015-11-01 10:29:36
  • 928

设计模式-模板方法模式(Go语言描述)

这篇文章我们还是继续我们的设计模式系列, 今天我们带来的一个全新的设计模式在实际开发中大家肯定都遇到过, 可能大家只是不知道它叫模板方法模式而已, 今天我们就来详细的说一下什么是模板方法模式,已经该模...
  • qibin0506
  • qibin0506
  • 2016-06-24 09:05:16
  • 5250

Java开发中的23种设计模式详解----命令模式(Command)

命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其...
  • sjyttkl
  • sjyttkl
  • 2017-06-21 12:23:41
  • 1620

设计模式之命令模式---Command Pattern

模式的定义命令模式是一个高内聚的模式,定义如下:Encapsulate a request as an object,thereby letting you parameterize clients ...
  • hfreeman2008
  • hfreeman2008
  • 2016-08-06 10:37:34
  • 2179

设计模式C++实现——命令模式

模式定义:         命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。         命令对象将动作和接受者包进对象中,这个对象只暴...
  • walkerkalr
  • walkerkalr
  • 2014-06-10 16:14:33
  • 1001
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 68万+
    积分: 7046
    排名: 4050
    友情链接

    鸿洋_

    Aggie的博客

    梁肖技术中心

    极客导航

    文章分类
    博客专栏
    最新评论