命令模式
命令模式(Command Pattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式
在软件开发中,我们经常需要向某些对象发送请求(调用其中的某个或某些方法),但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,此时,我们特别希望能够以一种松耦合的方式来设计软件,使得请求发送者与请求接收者能够消除彼此之间的耦合,让对象之间的调用关系更加灵活,可以灵活地指定请求接收者以及被请求的操作。命令模式为此类问题提供了一个较为完美的解决方案
通俗理解:将军发布命令,士兵去执行
示例1
以家里的智能遥控器为例。如果按钮的功能与执行耦合,比如有两排按钮,第一排控制电灯,第二排控制电视 ,如果有人想定制化,将第一排改成电视控制,第二排改成电灯控制,将会非常困难
- 抽象命令
public interface Command {
/**
* 执行
*/
void execute();
/**
* 撤销
*/
public void undo();
}
- 空命令
命令,不执行任何操作,可以省去为空判断
public class NoCommand implements Command {
@Override
public void execute() {
}
@Override
public void undo() {
}
}
- 电灯打开命令
public class LightOnCommand implements Command {
private LightReceiver lightReceiver;
public LightOnCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
@Override
public void execute() {
lightReceiver.on();
}
@Override
public void undo() {
lightReceiver.off();
}
}
- 电灯关闭命令
public class LightOffCommand implements Command {
private LightReceiver lightReceiver;
public LightOffCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
@Override
public void execute() {
lightReceiver.off();
}
@Override
public void undo() {
lightReceiver.on();
}
}
- 电灯执行者
public class LightReceiver {
public void on() {
System.out.println(" 电灯打开了.. ");
}
public void off() {
System.out.println(" 电灯关闭了.. ");
}
}
- 电视打开命令
public class TVOnCommand implements Command {
private TVReceiver tvReceiver;
public TVOnCommand(TVReceiver tvReceiver) {
this.tvReceiver = tvReceiver;
}
@Override
public void execute() {
tvReceiver.on();
}
@Override
public void undo() {
tvReceiver.off();
}
}
- 电视关闭命令
public class TVOffCommand implements Command {
private TVReceiver tvReceiver;
public TVOffCommand(TVReceiver tvReceiver) {
this.tvReceiver = tvReceiver;
}
@Override
public void execute() {
tvReceiver.off();
}
@Override
public void undo() {
tvReceiver.on();
}
}
- 电视执行者
public class TVReceiver {
public void on() {
System.out.println(" 电视机打开了.. ");
}
public void off() {
System.out.println(" 电视机关闭了.. ");
}
}
- 遥控器类
public class RemoteController {
// 打开功能按钮
Command[] onCommands;
// 关闭功能按钮
Command[] offCommands;
// 执行撤销的命令
Command undoCommand;
public RemoteController() {
onCommands = new Command[2];
offCommands = new Command[2];
for (int i = 0; i < 2; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
public void setCommand(int index, Command onCommand, Command offCommand) {
onCommands[index] = onCommand;
offCommands[index] = offCommand;
}
// 按下开按钮
public void onButtonPushed(int index) {
// 找到你按下的开的按钮, 并调用对应方法
onCommands[index].execute();
// 记录这次的操作,用于撤销
undoCommand = onCommands[index];
}
// 按下开按钮
public void offButtonPushed(int index) {
// 找到你按下的关的按钮, 并调用对应方法
offCommands[index].execute();
// 记录这次的操作,用于撤销
undoCommand = offCommands[index];
}
// 按下撤销按钮
public void undoButtonPushed() {
undoCommand.undo();
}
}
- 测试类
public class Command01Test {
public static void main(String[] args) {
RemoteController remoteController = new RemoteController();
LightReceiver lightReceiver = new LightReceiver();
TVReceiver tvReceiver = new TVReceiver();
remoteController.setCommand(0, new LightOnCommand(lightReceiver), new LightOffCommand(lightReceiver));
remoteController.setCommand(1, new TVOnCommand(tvReceiver), new TVOffCommand(tvReceiver));
remoteController.onButtonPushed(0);
remoteController.onButtonPushed(1);
remoteController.offButtonPushed(0);
remoteController.undoButtonPushed();
/**
* 电灯打开了..
* 电视机打开了..
* 电灯关闭了..
* 电灯打开了..
*/
}
}
总结
-
优点
- 降低系统的耦合度。由于请求者与接收者之间不存在直接引用,因此请求者与接收者之间实现完全解耦,相同的请求者可以对应不同的接收者,同样,相同的接收者也可以供不同的请求者使用,两者之间具有良好的独立性
- 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令
- 容易实现对请求的撤销和重做
-
缺点
- 可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意
-
适用场景
- 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
- 系统需要将一组操作组合在一起,即支持宏命令
- 系统需要在不同的时间指定请求、将请求排队和执行请求
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。