首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

【设计形式攻略】行为型模式之Command模式

2013-10-24 
【设计模式攻略】行为型模式之Command模式概要一种行为触发另一种行为,这是程序控制中最基本的逻辑。触发的形

【设计模式攻略】行为型模式之Command模式
概要一种行为触发另一种行为,这是程序控制中最基本的逻辑。触发的形式,可以有很多种,比如我们经常通过一系列命令或指令来区分不同的触发行为,而在实现的过程中,很多人容易犯这样一个错误,就是把触发方与执行方强耦合在一起,当处理逻辑简单,命令种类不多时,倒并不会有太多问题,但是当程序构架复杂,处理流多样化时,往往会带来诸多不便,甚至引起灾难性的后果。本文想介绍的Command模式,就是一种处理命令执行的形式,一种把行为封装于命令对象,对触发方和执行方之间错综复杂的关系进行解耦的一种模式。
目的Command模式最大的作用是对命令触发方与命令执行方之间的解耦,这也是使用该模式的目的所在,如果你的实现方式没有起到这样的效果,那就偏离了Command模式的真正价值所在。
实例可以考虑这样一个例子,Invoker接受到命令后需要决定对应的执行者,然后调用执行,初步设计如下:【设计形式攻略】行为型模式之Command模式
Invoker收到命令后通过参数判断决定具体的执行者,然后调用并执行处理,初看很简单的逻辑,但是从OOD的角度来看,这样的设计无疑是强耦合的,Invoker跟所有Performer都耦合在了一起,可以预见的是,在随着Performer数量的增加,Invoker中会有一堆的if&elseif&else的处理,而每个Performer中也会存在一堆重复逻辑的代码,庞大而冗余。每增加一种Performer,都会重复写着很多同样的逻辑代码,强耦合导致可扩展性无从谈起,单元测试无从做起,随着命令的不断膨胀,代码维护痛苦不堪。所以这里可以考虑Command模式,帮助解耦,Command模式很简单,就是把命令的行为封装成Command对象,每个Command对象的都需要重写execute方法来处理命令本身的执行逻辑,类图如下:【设计形式攻略】行为型模式之Command模式

Invoker在dispatch时获得对应的Command对象,然后执行对应execute方法,而每个具体命令的execute中执行对应performer的action。有些人肯定会有疑问,平白多出几个类,也没见有什么特别的,有用吗?那这么做到底带来了什么好处呢?首先,我们保证Invoker从此不在耦合于Performer,完全各干各的事,老死不相来往。Invoker只要提供给它Command对象,执行对应的execute方法,就会触发相应的Performer。其次,当从命令到触发Performer间需要传递很多参数时,Command的封装就让实现变得非常简单,我们只需要把相关参数封装于ConcreteCommand中,在触发Performer时传递给对应的action就可以了。在Client创建Command时初始化完毕,在Invoker分发时则完全不需要再关心这些细节,永远都是很简单的execute调用,试想如果按照初始方案,Invoker需要考虑每个Performer需要的参数并加以区别,所以Command模式让参数化变得简单。再次,可以很容易的实现异步命令。当有些命令需要异步执行时,那么只需要在对应的ConcreteCommand中给对应Service服务发送消息,由Service服务接受到消息命令后处理就可以了。不需要Invoker再去考虑各种命令的处理细节,繁琐而不易维护。最后,如果希望有类似命令撤销的操作,那么也可以在相关Command中提供状态机和数据备份的机制,支持前后状态的恢复和切换就可以实现。试想,如果按照第一中方案,把所有这些逻辑都放在Invoker中,会是多么可怕的一件事情。到这里,不知道是否能够体会到Command模式带来的一些好处。
应用在实际应用中,需要注意Command模式的目的是为Invoker和ConcreteCommand进行解耦,所以如果你的实现让Invoker耦合与具体命令时,则说明违反了这个原则,也失去了它的真正意义,其实从上面类图可以看出,ConcreteCommand一般都是由Invoker以外的模块来初始化创建,这其实也是为了让Invoker和ConcreteCommand完全解耦。另外,如果大家还记得Compositor模式的话,可以结合起来实现组合Command,具体实现请参考【设计模式攻略】结构型模式之Composite模式



热点排行