命令模式
命令模式的封装性非常好,把请求方(Invoker)和执行方(Receiver)分开,扩展性也非常好。
定义
将一个请求封装成一个对象,从而使得不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

实现
Receiver
抽象接收者,定义每个接收者都必须完成的业务。
1 2 3
| public abstract class Receiver{ public abstract void doSomething(); }
|
具体的Receiver
1 2 3 4 5 6 7
| public class Concrete1Reveiver extends Receiver{ public void doSomething(){} }
public class Concrete2Reveiver extends Receiver{ public void doSomething(){} }
|
Command
不同的命令实现都需要继承该类,实现自己的execute逻辑。
1 2 3
| public abstract class Command{ public abstract void execute(); }
|
具体的命令实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class ConcreteCommand1 extends Command{ private Receiver receiver; public ConcreteCommand1(Receiver receiver){ this.receiver = receiver; } public void execute(){ this.receiver.doSomething(); } }
public class ConcreteCommand2 extends Command{ private Receiver receiver; public ConcreteCommand2(Receiver receiver){ this.receiver = receiver; } public void execute(){ this.receiver.doSomething(); } }
|
Invoker
1 2 3 4 5 6 7 8 9
| public class Invoker{ private Command command; public void setCommand(Command command){ this.command = command; } public void action(){ this.command.execute(); } }
|
Use
1 2 3
| Invoker invoker = new Invoker(); invoker.setCommand(new ConcreteCommand1(new Concrete1Reveiver())); invoker.action();
|
模式应用
优点
- 解耦
调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需要调用Command抽象类的execute方法即可,不需要了解是哪个接收者执行。
- 可扩展性好
Command子类可以非常容易的扩展,调用者Invoker和高层的模块Client不产生严重的代码耦合。
- 与其他模式混合使用
与责任链模式结合,实现命令族解析任务
与模版方法结合,减少Command子类膨胀的问题。
缺点
Command的子类会随着命令的增多逐步膨胀。
命令的撤销
反命令
通过相反的命令来实现命令的撤销。
结合备忘录模式
结合备忘录模式还原最后状态,折中发昂发适合接收者为状态的变更情况,而不适合事件处理。
代码实例
假设有个录音机,录音机面板有三个按钮, play, rewind, stop。
需要根据三个按钮作出相应的反馈。
Receiver
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class AudioPlayer {
public void paly(){ System.out.println("Play"); }
public void rewind(){ System.out.println("Rewind"); }
public void stop(){ System.out.println("Stop"); } }
|
Command
不同的Command调用不同的Receiver命令。
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
| public abstract class Command {
protected static AudioPlayer audioPlayer = new AudioPlayer();
public abstract void execute();
}
public class PlayCommand extends Command { @Override public void execute() { super.audioPlayer.paly(); } }
public class RewindCommand extends Command { @Override public void execute() { audioPlayer.rewind(); } }
public class StopCommand extends Command { @Override public void execute() { audioPlayer.stop(); } }
|
Invoker
用于转发Command
1 2 3 4 5 6 7 8 9 10 11
| public class KeyPad { private Command command;
public void setCommand(Command command) { this.command = command; }
public void action() { this.command.execute(); } }
|
Use
1 2 3 4 5 6 7
| KeyPad keyPad = new KeyPad();
keyPad.setCommand(new RewindCommand()); keyPad.action();
keyPad.setCommand(new StopCommand()); keyPad.action();
|
如果后期需要增加一个按钮,stopAndRewind(),直接增加一个Command子类即可,其他地方不需要动。
1 2 3 4 5 6 7 8
| public class StopAndRewindCommand extends Command {
@Override public void execute() { audioPlayer.stop(); audioPlayer.rewind(); } }
|