"围观"设计模式(23)--行为型之命令模式(Command Pattern)
设计模式,架构设计,行为型设计模式,命令模式,CommandPattern2016-06-25
在面向对象程式设计的范畴中,命令模式是一种设计模式,它尝试以物件来代表实际行动。命令物件可以把行动(action) 及其参数封装起来,于是这些行动可以被:
这些都是现代大型应用程序所必须的功能,即“复原”及“重复”。----WIKIPEDIA
命令模式是一个高内聚的模式,它将一个请求封装为一个对象,让你使用不同的请求将客户端参数化,在项目中应用比较广泛,他的封装性比较好,将请求方和接收方分离开来,扩展性较好。命令模式中主要有三种角色,一个是命令的接受者(Receiver),他负责对于收到的命令作出响应。一个是命令(Command)角色,他负责定义接受者需要执行什么样的命令。另一个是调用者(Invoker),接收命令调用并执行命令。但是命令模式也存在不足,如果命令较多的时候那么会存在多个子类,导致臃肿,可以结合其他的模式进行设计,如结合责任链模式实现命令的解析、结合模板方法模式减少子类的膨胀问题。
1. 接收者(Receiver)
负责具体执行哪些动作,也就是说他只负责提供一些任务的具体实现,不负责其他的部分。
2. 命令(Command)角色
负责定义好具体的命令,包括规定好接收者需要执行的哪些动作。
3. 调用者(Invoker)角色
负责调用命令执行,不需要知道谁是接收者,以及接收者怎么去执行,因为需要知道怎么执行的是接收者,他定义了任务的具体实现,另外不需要知道接收者是谁,这在命令角色中已经定义了哪些接收者执行哪些动作。
接收者角色:
public interface Receiver { public void doSomthing(); }
public class Receiver1 implements Receiver { @Override public void doSomthing() { System.out.println("Receiver1"); } }
public abstract class Command { protected Receiver receiver; public Command(Receiver receiver) { this.receiver = receiver; } public abstract void execute(); }
public class Command1 extends Command { public Command1(Receiver receiver) { super(receiver); } @Override public void execute() { this.receiver.doSomthing(); } }
public class Invoker { private Command command; public void setCommand(Command command) { this.command = command; } public void action() { this.command.execute(); } }
public class Test { public static void main(String[] args) { // 调用者 Invoker invoker = new Invoker(); // 接收者 Receiver receiver = new Receiver1(); // 命令角色 Command command = new Command1(receiver); invoker.setCommand(command); invoker.action(); } }
以家庭雇佣管家和保姆等佣人为例子,主要的人物有,老板、佣人,其中老板在命令模式中相当于调用者,而佣人则相当于接收者,老板对于佣人的指令相当于命令角色。那么从这一点出发来想这个案例中老板发号施令的好处所在,老板只需要说一下命令,然后,具体谁去做,怎么做老板不需要知道的,只需要等待命令的结果就行了。
接收者角色
public interface Person { /** * 劈柴 */ public void chopping(); /** * 做饭 */ public void makeFood(); /** * 喂马 */ public void feedHorse(); /** * 周游世界 */ public void travelWorld(); }
public class Man implements Person{ @Override public void chopping() { System.out.println("Man --- chopping"); } @Override public void makeFood() { System.out.println("Man --- makeFood"); } @Override public void feedHorse() { System.out.println("Man --- feedHorse"); } @Override public void travelWorld() { System.out.println("Man --- travelWorld"); } }
public class Woman implements Person{ @Override public void chopping() { System.out.println("Woman --- chopping"); } @Override public void makeFood() { System.out.println("Woman --- makeFood"); } @Override public void feedHorse() { System.out.println("Woman --- feedHorse"); } @Override public void travelWorld() { System.out.println("Woman --- travelWorld"); } }
public abstract class Command { protected Man man = new Man(); protected Woman woman = new Woman(); public abstract void executeBossCommand(); }具体实现类
public class ChoppingCommand extends Command { @Override public void executeBossCommand() { this.man.chopping(); } }
public class MakeFoodCommand extends Command { @Override public void executeBossCommand() { this.woman.makeFood(); } }
public class Boss { private Command command; public void setCommand(Command command) { this.command = command; } public void executeCommand(){ this.command.executeBossCommand(); } }
public class MainTest { public static void main(String[] args) { Boss boss = new Boss(); Command command1 = new ChoppingCommand(); boss.setCommand(command1); boss.executeCommand(); Command command2 = new MakeFoodCommand(); boss.setCommand(command2); boss.executeCommand(); } }
假如此时老板很明确的是男的佣人要去劈柴和喂马,而女佣人可以去做饭和旅游,那么这种情况下是不是可以进行扩展呢?
代码分析,如果说可以扩展的话,那么其余的部分需要进行变更,也就是在上面例子的基础上只需要扩展子类即可,那么这里我不再列出其类的结构图了,因为基本是一致的。
扩展命令角色为ManCommand和WomanCommand两个具体的实现类。
ManCommand
public class ManCommand extends Command{ /** * 让男人干点劈柴喂马的事 */ @Override public void executeBossCommand() { this.man.chopping(); this.man.feedHorse(); } }
public class WomanCommand extends Command{ /** * 让女人干点做饭和周游世界的事 */ @Override public void executeBossCommand() { this.woman.makeFood(); this.woman.travelWorld(); } }
public class MainTest { public static void main(String[] args) { Boss boss = new Boss(); ManCommand manCommand = new ManCommand(); boss.setCommand(manCommand); boss.executeCommand(); WomanCommand womanCommand = new WomanCommand(); boss.setCommand(womanCommand); boss.executeCommand(); } }从此案例可以看出命令模式的确扩展性很强,符合开闭原则。
1. 解耦:调用者和接受者之间没有关系,调用者在调用的时候,只需要执行命令(Command)中的执行方法就可以了,不需要了解哪个接收者去实际的执行。
2. 可扩展性:Command部分容易扩展,调用者不需要知道有什么改变,维持原有的设计即可完成扩展,从这点上看,符合开闭原则,对修改关闭对于扩展开放。
命令过多的时候,会导致子类过多,系统类臃肿且难于维护,不过可以结合其他的设计模式进行整合,使得优点得到更好的发挥,如结合模板方法模式解决子类过多的问题。
只要可认为是命令的地方都可以采用命令模式,比如,按钮的点击和拖拽,相当于两个命令,而按钮作为接受者,此时就可以采用命令模式进行设计。
源码下载