引言
设计模式部分马上就要结尾,终于系统性的写完了一块。先放出上一节的备忘录模式。这节我们说说命令模式。
示例地址
类图
image定义
将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
命令模式的使用场景
1. 需要抽象出待执行的动作,然后以参数的形式提供出来类似于过程设计中的回调机制,而命令模式正是回调机制的一个面向对象的替代品。
2. 在不同的时刻指定、排列和执行请求。一个命令对象可以有与初始请求无关的生存期。
3. 需要支持取消操作。
4. 支持修改日志功能,这样当系统崩溃时,这些修改可以被重做一遍。
5. 需要支持事务操作。
命令模式中的角色
Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。
Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理。
经典示例
1. 接收者
/**
* 接收者
*
* @author 512573717@qq.com
* @created 2018/8/13 下午3:20.
*/
public class Receiver {
public void action() {
System.out.println("我来执行任务");
}
}
2. 命令接口
/**
* 命令接口
*
* @author 512573717@qq.com
* @created 2018/8/13 下午3:14.
*/
public interface ICommand {
public void execute();
}
3. 命令接口的实现
/**
* 命令接口的实现
*
* @author 512573717@qq.com
* @created 2018/8/13 下午3:14.
*/
public class ConcreteCommand implements ICommand {
private Receiver mReceiver;
public ConcreteCommand(Receiver receiver) {
mReceiver = receiver;
}
@Override
public void execute() {
mReceiver.action();
}
}
4. 调用者
/**
* 调用者
*
* @author 512573717@qq.com
* @created 2018/8/13 下午3:21.
*/
public class Invoker {
/**
* 持有命令对象
*/
private ICommand command = null;
/**
* 设置调用者持有的命令对象
*
* @param command 命令对象
*/
public void setCommand(ICommand command) {
this.command = command;
}
/**
* 示意方法,要求命令执行请求
*/
public void runCommand() {
//调用命令对象的执行方法
command.execute();
}
}
5. Client
//经典示例
ConcreteCommand concreteCommand = new ConcreteCommand(new Receiver());
Invoker invoker = new Invoker();
invoker.setCommand(concreteCommand);
invoker.runCommand();
实际运用
生活中存在很多这样的案例,例如我们通过开关可以控制一些电器的打开和关闭,例如电灯或者油烟机。开关与电器之间通过电线建立连接,如果开关打开,则电线通电,电器工作;反之,开关关闭,电线断电,电器停止工作。
在命令模式中,发送者与接收者之间引入了新的命令对象(电线),将发送者的请求封装在命令对象中,再通过命令对象来调用接收者的方法,从而实现解耦。
1. 开灯 关灯实际接收者
/**
* 开灯 关灯实际接收者
*
* @author 512573717@qq.com
* @created 2018/8/13 下午4:58.
*/
public class LightReceiver {
public void on() {
System.out.println("开灯");
}
public void off() {
System.out.println("关灯");
}
}
2. 油烟机的接收者
/**
* 油烟机的接收者
*
* @author 512573717@qq.com
* @created 2018/8/13 下午5:12.
*/
public class ExhaustReceiver {
public void on() {
System.out.println("开油烟机");
}
public void off() {
System.out.println("关油烟机");
}
}
3. 命令接口
/**
* 命令接口
*
* @author 512573717@qq.com
* @created 2018/8/13 下午3:14.
*/
public interface ICommand {
public void execute();
}
4. 开灯 关灯命令
/**
* 开灯 关灯命令
*
* @author 512573717@qq.com
* @created 2018/8/13 下午4:48.
*/
public class LightCommand implements ICommand {
private LightReceiver mLightReceiver;
public LightCommand(LightReceiver lightReceiver) {
mLightReceiver = lightReceiver;
}
@Override
public void execute() {
mLightReceiver.on();
mLightReceiver.off();
}
}
5. 开 关 吸油烟机命令
/**
* 开 关 吸油烟机命令
*
* @author 512573717@qq.com
* @created 2018/8/13 下午4:51.
*/
public class ExhaustCommand implements ICommand {
private ExhaustReceiver mExhaustReceiver;
public ExhaustCommand(ExhaustReceiver exhaustReceiver) {
mExhaustReceiver = exhaustReceiver;
}
@Override
public void execute() {
mExhaustReceiver.on();
mExhaustReceiver.off();
}
}
6. 调用者
/**
* 调用者
*
* @author 512573717@qq.com
* @created 2018/8/13 下午3:21.
*/
public class Invoker {
/**
* 持有命令对象
*/
private ICommand command = null;
/**
* 设置调用者持有的命令对象
*
* @param command 命令对象
*/
public void setCommand(ICommand command) {
this.command = command;
}
/**
* 示意方法,要求命令执行请求
*/
public void runCommand() {
//调用命令对象的执行方法
command.execute();
}
}
7. Client
//开关案例
Invoker invoker=new Invoker();
LightCommand lightCommand = new LightCommand(new LightReceiver());
ExhaustCommand exhaustCommand = new ExhaustCommand(new ExhaustReceiver());
// 请求
System.out.println("开灯 关灯命令=============");
invoker.setCommand(lightCommand);
invoker.runCommand();
System.out.println("开油烟机 关油烟机命令=============");
invoker.setCommand(exhaustCommand);
invoker.runCommand();
总结
优点
- 降低系统的耦合度
- 新的命令可以很容易地加入到系统中
- 可以比较容易地设计一个命令队列或宏命令
缺点
- 使用命令模式可能会导致某些系统有过多的具体命令类
网友评论