无用的设计模式之命令模式
前言
本文不是主要介绍什么是命令模式,而是对命令模式在使用上的一种思考,想看模式介绍的话,估计你要失望了。但是你起码得知道什么是命令模式吧,要不接下来要被误导了。
从类图出发
我们先起码抛弃个人对模式的一种无条件信仰,来看一下定义这个模式的定义类图,你到其他博客上看,估计也是类似的类图。
看这个类图,你大概也发现了问题。
1,client怎么和invoker没有联系?代码写出来可不是这个结果,client起码要调用invoker。
2,receiver的关系就算依赖注入,那也是command的主体啊,起码是当作成员变量的,要不Invoker怎么执行呢?
根据这些问题重新整理这个类图。
好了,这个基本才是真正按照命令模式写代码写出来的效果,不要感觉好奇感,模式只是提出一种思想,就是一个模版的类图,但不是我们认真根据代码画的类图,所以这个类图才变成这个样子。
从故事出发
根据我们想到的问题,然后修改类图,来实际看看我们使用的场景,命令模式嘛,我们就演绎一个故事吧,这样便于理解。我们把client就当作皇帝(顾客就是上帝,你懂的),invoker就是将军(一个调度者),receiver就是军队(真正执行命令的对象)。
假如没有命令模式,那就是顺序编程咯,皇帝带步兵,骑兵攻城略地。假如攻打另一个地方,皇帝就继续御驾亲征,带兵去打。每打一个地方就是皇帝带兵打,这样皇帝就累了,历史上皇帝御驾亲征的情况还是少数(创业团队的话,那是还没当上皇帝,不算的)。
那用命令模式的话,皇帝就要启用将军了,场景就变了,皇帝下个命令,让将军带骑兵,带步兵,带运粮官出征,于是将军根据命令带着骑兵,带步兵,带运粮官去打仗了。(打仗的永远都是兵,他们才是历史的创造者)。
上面的故事就是我们见到的命令模式,但是你也感觉哪里不对劲啊,皇帝还必须知道自己有步兵多少,骑兵多少,要不没法下命令了,这完全和电视上演的不一样啊,所以我们按照实际皇帝的做法,让军队和将军更加亲密(此处不提黄袍加身的玩法,因为程序不会背叛,独立,政变),皇帝的命令就变简单了,直接说攻打某座城池就行,将军自己会对命令进行分析,带合适的兵去打仗。这样皇帝也是最轻松的。
杯酒释兵权的情况就是怕造反,程序不会造反,所以按照调用最省心的方法来。最终版的类图如下。
分析最终版
执行命令的对象和命令相关,这样好吗,从扩展角度讲不好,但是从实际使用的情况来看,一个功能的实现是需要特定的对象来做的。并不是随机挑出来的都可以,所以在实用角度讲这样算是一种最佳实践了,其实出现一个任务能很多对象都能做的情况,这个模式也需要做最佳选择(就算排序算法很多,java集合自带的排序还是一种增强版的归并排序(jdk1.6))。
client只要和命令和接受命令的人相关就好,至于他怎么做,再也不用管了,这样其实也带来一定麻烦,就是命令太多怎么办?
如果数量中等的话,且调用者不会增加,那么可以使用模版方法来控制,如果命令的生命周期短且不经常使用的话,那么直接考虑写匿名内部类。
如果数量巨多,那可能这个模式已经不适合了,命令太多了,客户端调用也是问题,我们提供的太多了,给调用我们写的代码的人也是苦恼,就接触Linux一样,命令那么多,不过常用的命令还是可数的,要不不查看手册是不行了。
但是命令的更换,他还是有不错的表现的,你其实只想要几条命令,剩下的都是依靠新的做法替换旧的做法,满足了开闭原则了。
最后说几句
最初提出的命令模式实际在现实中不常用,用的都是改变版的,所以在此文中认为他没用。
命令模式的试用场景:
1, 命令可以预计,预计不到的就慎用了,不要用出一堆命令来,自己人调用都很麻烦 。
2, 有回退的需要的场景,简单回退的场景,命令模式很合适,当然假如备忘录模式也是可以的,或者选择备忘录模式(这个看场景)。
3, 遇到的问题往往的旧的替换新的,命令已经保持高内聚,低耦合了。完全满足需要。