每周学点设计模式(3)——命令模式,设计模式命令
分享于 点击 16865 次 点评:170
每周学点设计模式(3)——命令模式,设计模式命令
概述
在面向对象编程中,命令模式属于行为型(behavior)设计模式,用于“行为发送者”与“行为接收者”之间的解耦。(行为发送者为发起某个操作的对象,接收者为执行该操作请求的对象)。命令模式的结构如下图所示:

命令模式结构图
命令模式的常见使用场景有:
- Java 菜单项和按钮的动作处理
- 为宏(复合命令)提供支持(记录和回退的宏操作)
- “undo”操作
- Java进度条
- 日志、请求队列等
使用命令模式实现事务
假定需要TCP端口连接的用于接受和处理用户请求事务的服务器,这些事务包含很多命令。如果使用switch语句在case中调用每个命令,会导致程序耦合度增加,不符合面向对象设计思想。将这些命令封装为对象将请求者和接受者解耦,这样的设计更加合适。
import java.util.*; final class 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
是命令接收者角色,实现了所有的命令处理方法,同时它作为单例实现。
class CommandManager { private Command myCommand; public CommandManager(Command myCommand) { this.myCommand = myCommand ; } public void runCommands( ) { myCommand.execute(); } }
CommandManager
是调用者角色,它的私有变量myCommand
传入TransactionCommand
对象。当runCommands()
被调用时,选择合适的TransactionCommand
对象的方法。
class TransactionCommand implements Command { 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 i = 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
对象中。
class CommandArgument { private int[] args; CommandArgument() { args = new int[2]; } public int[] getArguments() { return args; } public void setArgument(int i1, int i2) { args[0] = i1; args[1] = i2; } }
CommandArgument
是辅助类,用来保存命令参数。
public class 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 main(String[] args) { 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的实现类是接收者和调用者的桥梁,接收者与命令实现类相关联,调用者发出请求到某个命令。
- 具体的请求封装为命令对象,将命令存储在调用者对象中,使得不同动作的组合以及动作记录更加容易实现。
- 增加新的命令时,不需要修改已有的代码。
- 缺点:可能导致系统有过多的命令类以及复杂的关联关系。
用户点评