Pulpcode

捕获,搅碎,拼接,吞咽

0%

从python到java设计模式之命令模式

最近在看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被运行。

commandpattern

java实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface ICommand{
public void Execute();
}

public class CopyCommand implements ICommand{
public void Execute(){
xxxx
xxxx
}
}

public class PasteCommand implements ICommand{
public void Execute(){
xxxx
xxxx
}
}

public Class MenuItem{
private ICommand command;

public void Clicked(){
this.command.Execute();
}
}

python实现

用python实现命令模式的话,有一点有趣的是,你可以”执行”一个对象,就像执行一个函数一样,只要这个对象实现了__call__方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 注意以下试图将撤销和重做打包成完整命令。
class Command(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()

# 试图定义一个宏

class Macro(object):
def __init__(self):
self.__commands = []

def add(self, command):
self.__commands.append(command)

def __call__(self):
for command in self.__commands:
command()

do = __call__

def undo(self):
for command in reversed(self.__commands):
command.undo()