最近在看Hystrix,有博客提到这个里面使用到了命令模式。虽然命令模式在web开发中很少见,但神奇的是我也在前段时间的一次设计中使用了命令模式(或者说类似的模式)。
命令模式算是一个比较特别的模式,为什么说它特别?因为很多教你如何做好oop设计的书都会提到类似的观点:
不要把操作变成类。
然而命令模式就是把某一个操作封装成为类。
简单的说命令模式干了这样一件事:
一开始你的程序是A,B,C…对象对X,Y,Z…对象的直接操作。然后为了让(A,B,C)和(X,Y,Z)解耦,你在A和B之间加入了一个中介对象F1,F2,F3,这个中介对象的意义是包装对X,Y,Z的操作。这样你的(A,B,C)就不直接操作(X,Y,Z)了,而是使用(F1,F2,F3)对象,而这个F对象就被称为命令。
这样的好处是,这些操作可以重用。而且A,B,C与X,Y,Z是解耦的,A,B,C并不知道自己在操作什么对象,实际上他们也不知道自己在使用什么命令,它们仅仅是在调用Command的execute而已。
特别注意打包对象F1,F2,F3,和(X,Y,Z)并不是解耦的,命令对象会很清楚的知道自己在跟谁打交道。
需要理解命令模式的是,命令模式并不仅仅是解耦操作对象与被操作对象之间的关系,更重要的是,它提供了一种对象命令建模的方式。这一点也就是设计模式中所提到的命令模式所能支持的宏或者取消(undo)和重做(redo)。hystrix中对一个容错操作建模,也是为了对这个动作的一系列打包(类似提供一系列钩子),比如在这个操作之前做什么,在这个操作之后做什么,这个操作成功了要做什么,这个操作失败了要做什么,等等。
在《设计模式》提到的例子是,图形界面的菜单下拉,每一个MenuItem在被点击(调用client)的时候,才会知道哪个command被运行。
java实现
1 | public interface ICommand{ |
python实现
用python实现命令模式的话,有一点有趣的是,你可以”执行”一个对象,就像执行一个函数一样,只要这个对象实现了__call__方法。
1 | # 注意以下试图将撤销和重做打包成完整命令。 |