本文作者: ImportNew -
hejiani 未经许可,禁止转载!
概述
在面向对象编程中,命令模式属于行为型(behavior)设计模式,用于“行为发送者”与“行为接收者”之间的解耦。(行为发送者为发起某个操作的对象,接收者为执行该操作请求的对象)。命令模式的结构如下图所示:
命令模式的常见使用场景有:
- Java 菜单项和按钮的动作处理
- 为宏(复合命令)提供支持(记录和回退的宏操作)
- “undo”操作
- Java进度条
- 日志、请求队列等
使用命令模式实现事务
假定需要TCP端口连接的用于接受和处理用户请求事务的服务器,这些事务包含很多命令。如果使用switch语句在case中调用每个命令,会导致程序耦合度增加,不符合面向对象设计思想。将这些命令封装为对象将请求者和接受者解耦,这样的设计更加合适。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import
final CommandReceiver { private int [] c; private CommandArgument a; private CommandReceiver(){ c = new int [ 2 ]; } private static CommandReceiver cr = new CommandReceiver(); public static CommandReceiver getHandle() { return cr; } public void setCommandArgument(CommandArgument a) { this .a = a; } public void methAdd() { c = a.getArguments(); System.out.println( "The result is " + (c[ 0 ]+c[ 1 ])); } public void methSubtract() { c = a.getArguments(); System.out.println( "The result is " + (c[ 0 ]-c[ 1 ])); } } |
CommandReceiver
是命令接收者角色,实现了所有的命令处理方法,同时它作为单例实现。
1
2
3
4
5
6
7
8
9
|
class
private Command myCommand; public CommandManager(Command myCommand) { this .myCommand = myCommand ; } public void runCommands( ) { myCommand.execute(); } } |
CommandManager
是调用者角色,它的私有变量myCommand
传入TransactionCommand
对象。当runCommands()
被调用时,选择合适的TransactionCommand
对象的方法。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
class
implements
private CommandReceiver commandreceiver; private Vector commandnamelist,commandargumentlist; private String commandname; private CommandArgument commandargument; private Command command; public TransactionCommand () { this ( null , null ); } public TransactionCommand ( Vector commandnamelist, Vector commandargumentlist){ this .commandnamelist = commandnamelist; this .commandargumentlist = commandargumentlist; commandreceiver = CommandReceiver.getHandle(); } public void execute( ) { for ( int
0 ; i < commandnamelist.size(); i++) { commandname = (String)(commandnamelist.get(i)); commandargument = (CommandArgument)((commandargumentlist.get(i))); commandreceiver.setCommandArgument(commandargument); String classname = commandname + "Command" ; try { Class cls = Class.forName(classname); command = (Command) cls.newInstance(); } catch (Throwable e) { System.err.println(e); } command.execute(); } } } class AddCommand extends TransactionCommand { private CommandReceiver cr; public AddCommand () { cr = CommandReceiver.getHandle(); } public void execute( ) {
cr.methAdd(); } } class SubtractCommand extends TransactionCommand { private CommandReceiver cr; public SubtractCommand () { cr = CommandReceiver.getHandle(); } public void execute( ) { cr.methSubtract(); } } |
TransactionCommand
对象的execute()
操作根据传递的命令名称列表的内容动态加载需要的命令子类(子类命名时遵守操作名 + “Command”的命名习惯)。
命令和参数存储在list中,封装在TransactionCommand
对象中。
1
2
3
4
5
6
7
8
9
10
11
12
|
class
private int [] args; CommandArgument() { args = new int [ 2 ]; } public int [] getArguments() { return args; } public void setArgument( int i1, int
args[ 0 ] = i1; args[ 1 ] = } } |
CommandArgument
是辅助类,用来保存命令参数。
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
32
33
34
35
36
37
38
39
|
public TestTransactionCommand { private Vector clist,alist; public TestTransactionCommand() { clist = new Vector();
alist = new Vector(); } public void clearBuffer(Vector c, Vector a) { clist.removeAll(c); alist.removeAll(a); } public Vector getClist() { return clist; } public Vector getAlist() { return alist; } public static void
CommandArgument ca,ca2; TestTransactionCommand t = new TestTransactionCommand(); ca = new CommandArgument(); ca.setArgument( 2 , 8 ); Vector myclist = t.getClist(); Vector myalist = t.getAlist(); myclist.addElement( "Add" ); myalist.addElement(ca); TransactionCommand tc = new TransactionCommand(myclist,myalist); CommandManager cm = new CommandManager(tc); cm.runCommands(); t.clearBuffer(myclist,myalist); ca2 = new CommandArgument(); ca2.setArgument( 5 , 7 ); myclist = t.getClist(); myalist = t.getAlist(); myclist.addElement( "Subtract" ); myalist.addElement(ca2); myclist.addElement( "Add" ); myalist.addElement(ca2); TransactionCommand tc2 = new TransactionCommand(myclist,myalist); CommandManager cm2 = new CommandManager(tc2); cm2.runCommands(); } } |
可见,客户端的代码不依赖于任何的TransactionCommand
子类,同时具有良好的可扩展性——需要增加新命令时可以定义子类并在CommandReceiver
类提供新的命令处理方法。
总结
- Command是整个模式的核心,Command的实现类是接收者和调用者的桥梁,接收者与命令实现类相关联,调用者发出请求到某个命令。
- 具体的请求封装为命令对象,将命令存储在调用者对象中,使得不同动作的组合以及动作记录更加容易实现。
- 增加新的命令时,不需要修改已有的代码。
- 缺点:可能导致系统有过多的命令类以及复杂的关联关系。