近在看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实现
public interfaceICommand{
publicvoidExecute();
}
public classCopyCommandimplementsICommand{
publicvoidExecute(){
xxxx
xxxx
}
}
public classPasteCommandimplementsICommand{
publicvoidExecute(){
xxxx
xxxx
}
}
public Class MenuItem{
private ICommand command;
publicvoidClicked(){
this.command.Execute();
}
}
  python实现
  用python实现命令模式的话,有一点有趣的是,你可以”执行”一个对象,像执行一个函数一样,只要这个对象实现了 call 方法。
  # 注意以下试图将撤销和重做打包成完整命令。
classCommand(object):
def__init__(self, do, undo):
assert callable(do) and callable(undo)
self.do = do
self.undo = undo
def__call__(self):
self.do()
command = Command()
command()
# 试图定义一个宏
classMacro(object):
def__init__(self):
self.__commands = []
defadd(self, command):
self.__commands.append(command)
def__call__(self):
for command in self.__commands:
command()
do = __call__
defundo(self):
for command in reversed(self.__commands):
command.undo()