原帖详见:http://javapapers.com/design-patterns/command-design-pattern/
命令设计模式是用于将请求封装成一个对象,并将其传递给一个调用者,在这里调用者并不知道怎样服务于这个请求,但是使用相应的命令可以执行响应的动作。
为了理解命令设计模式,我们应该理解相关的术语,例如客户端代码、命令、命令实现、调用者、接收者。
1. 命令(Command)是一个具有执行方法的接口,是整个约定(contract)的核心。
2. 客户端代码(Client)用于创建一个命令实现的实例,并将其与接收者(Receiver) 相关联。
3. 调用者(Invoker)知道命令执行响应的动作。
4. 命令的实现创建一个接收者和动作的绑定。
5. 接收者知道执行动作的真实的步骤。
命令模式的讨论
使用一个例子更容易理解上面的描述。我们考虑开发一个万能遥控器(universal remote)。我们的UniversalRemote有两个按钮,一个用于打开,一个用于关闭所关联的ConsumerElectronics。
对于ConsumerElectronic我们有两个实现,Television和SoundSystem。Button是一个动作的调用者。
OnCommand用于转换ConsumerElectronic的开关。当实例化OnCommand的时候需要设置接收者(receiver),在这里接收者是Television和SoundSystem。UnversalRemote类持有所有的接收者并提供一个方法确定当前活动的接收者。
当创建一个调用者的实例的时候,一个具体的命令要作为参数传递进去。调用者并不知道怎样执行一个动作。它要做的就是履行Command的约定。调用者调用具体命令的execute方法。
命令模式的UML图
命令模式的实现
Command.java
package com.designpatten.command;
/**
* 命令接口
* @author suifeng
*
*/
public interface Command {
void execute();
}
ConsumerElectronic.java
package com.designpatten.command;
/**
* 调用者接口
* @author suifeng
*
*/
public interface ConsumerElectronic {
void on();
void mute();
}
OnCommand.java
package com.designpatten.command;
/**
* "打开"命令的实现
* @author suifeng
*
*/
public class OnCommand implements Command {
private ConsumerElectronic ce;
public OnCommand(ConsumerElectronic ce) {
super();
this.ce = ce;
}
public void execute() {
this.ce.on();
}
}
MuteAllCommand.java
package com.designpatten.command;
import java.util.List;
/**
* "关闭全部"命令的实现
* @author Administrator
*
*/
public class MuteAllCommand implements Command {
private List<ConsumerElectronic> ceList;
public MuteAllCommand(List<ConsumerElectronic> ceList) {
super();
this.ceList = ceList;
}
public void execute() {
for (ConsumerElectronic ce : ceList) {
ce.mute();
}
}
}
UniversalRemote.java
package com.designpatten.command;
/**
* "万能遥控器类",用于获取活动的设备
* @author suifeng
*
*/
public class UniversalRemote {
public static ConsumerElectronic getActiveElectronic()
{
return new Television();
}
}
DemoCommandPatten.java
package com.designpatten.command;
import java.util.ArrayList;
import java.util.List;
/**
* 测试实现
* @author suifeng
*
*/
public class DemoCommandPatten {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 创建一个当前活动的设备
ConsumerElectronic ce = UniversalRemote.getActiveElectronic();
// 封装一个命令
Command onCommand = new OnCommand(ce);
// 创建调用者
Button button = new Button(onCommand);
// 开始调用
button.invoke();
System.out.println("================华丽的分割线=============");
ConsumerElectronic tv = new Television();
ConsumerElectronic ss = new SoundSystem();
List<ConsumerElectronic> ceList = new ArrayList<ConsumerElectronic>();
ceList.add(tv);
ceList.add(ss);
// 封装命令
Command muteCommand = new MuteAllCommand(ceList);
// 创建调用者
Button button2 = new Button(muteCommand);
button2.invoke();
}
}
命令模式的要点
1. 命令模式帮助实现调用者和接收者的解耦合,其中接收者知道怎样执行一个动作。
2. 命令模式可以帮助实现回调。
3. 增强了可扩展性,我们可以在不改变现有代码的基础上新增一个命令。
4. 命令模式定义了接收者和动作的绑定。
5. 一个命令应该能够实现重做和取消的功能。
JDK中的命令模式
java.lang.Runnable和javax.swing.Action都使用了命令模式。