在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)。
1、适用场景
(1)系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
(2)系统需要在不同的时间指定请求、将请求排队和执行请求。
2、模式分析
(1).命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
(2).每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
(3).命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
(4).命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
(5).命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
3、模式优点
(1).降低对象之间的耦合度。
(2).新的命令可以很容易地加入到系统中。
(3).可以比较容易地设计一个组合命令。
(4).调用同一方法实现不同的功能
4、模式缺点
使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
5、代码实现
(1)结构图
(2)实现代码
//模拟一个开关灯的操作命令
public class TestCommand {
public static void main(String[] args) {
Light testLight = new Light();
LightOnCommand testLOC = new LightOnCommand(testLight);
LightOffCommand testLFC = new LightOffCommand(testLight);
Switch testSwitch = new Switch(testLOC, testLFC);
testSwitch.flipUp( );
testSwitch.flipDown( );
}
}
//-----------------------------------------------------
//---------- Class Light ----------------------------
class Light {
public void turnOn() {
System.out.println("Light is on now !");
}
public void turnOff() {
System.out.println("Light is off now !");
}
}
//-----------------------------------------------------
//---------- Class Switch ---------------------------
class Switch {
private Command UpCommand, DownCommand;
public Switch (Command Up, Command Down) {
UpCommand = Up;
DownCommand = Down;
}
void flipUp() {
UpCommand.execute();
}
void flipDown() {
DownCommand.execute();
}
}
//-----------------------------------------------------
//---------- Class LightOnCommand -------------------
class LightOnCommand implements Command {
private Light myLight;
public LightOnCommand (Light L) {
myLight = L;
}
public void execute() {
myLight.turnOn();
}
}
//-----------------------------------------------------
//---------- Class LightOffCommand ------------------
class LightOffCommand implements Command {
private Light myLight;
public LightOffCommand (Light L) {
myLight = L;
}
public void execute() {
myLight.turnOff();
}
}