一 定义
命令模式也属于行为型设计模式之一。
定义:将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
所以,命令模式的本质是,封装请求。
二 模式结构
角色介绍
- Receiver:接收者角色。
该类是命令的具体执行者,负责具体实施或者执行一个请求,说的通俗一点,就是真正干活的角色。 - Command:命令角色
定义所有的具体命令类的抽象接口。 - ConcreteCommand:具体命令角色
该类实现了Command接口 - Invoker:请求者角色
该类的职责是调用命令对象执行具体的请求。 - Client:客户端
通用代码如下
- 抽象的命令接口
public interface Command {
/**
* 执行具体操作的命令
*/
void execute();
}
- 接收者类
public class Receiver {
/**
* 真正执行具体命令逻辑的方法
*/
public void action(){
System.out.println("执行具体的操作");
}
}
- 具体的命令类
public class ConcreteCommand implements Command{
private Receiver mReceiver;
public ConcreteCommand(Receiver receiver){
this.mReceiver=receiver;
}
@Override
public void execute() {
// 调用接收者的相关方法来执行具体逻辑
mReceiver.action();
}
}
- 请求者类
public class Invoker {
private Command mCommand; // 持有一个对应命令对象的引用
public Invoker(Command command){
this.mCommand=command;
}
public void action(){
// 调用具体命令对象的相关方法,执行具体命令
mCommand.execute();
}
}
- 客户端测试代码
// 构造一个接收者对象
Receiver receiver=new Receiver();
// 根据接收者对象构造一个命令对象
Command command=new ConcreteCommand(receiver);
// 根据具体的对象构造请求者对象
Invoker invoker=new Invoker(command);
// 执行请求方法
invoker.action();
三 实例
我们以遥控器遥控电视为例,以前的电视是没有遥控器的,你如果想换台的话,要跑到电视机前,手动按换台按键,非常麻烦。现在我们有了遥控器,如果想换台,按一下遥控器的换台按键,就可以实现换台。在这里,我们是通过遥控器发出的命令,所以遥控器相当于Invoker,命令发出者,我们相当于客户端,我们的责任是组装遥控器。遥控器上的每个具体按键,都是一个具体的命令。通过遥控器,就实现了我们和电视机之间的解耦。
- Receiver角色
Receiver是命令的具体执行者,我们在这里实现了四个命令逻辑,分别是,节目加,节目减,音量加,音量减。
/*
* Receiver角色,真正的命令执行者
* @author Jackson
* @version 1.0.0
* since 2019 05 09
*/
public class ChangeReceiver {
/**
* 真正处理节目加的逻辑
*/
public void addItem(){
System.out.println("节目+");
}
/**
* 真正处理节目减的逻辑
*/
public void subtractItem(){
System.out.println("节目-");
}
/**
* 真正处理音量加的逻辑
*/
public void addVoice(){
System.out.println("音量+");
}
/**
* 真正处理音量减的逻辑
*/
public void subtractVoice(){
System.out.println("音量-");
}
}
- 命令接口
public interface Command {
/**
* 执行具体操作的命令
*/
void execute();
}
- 具体的命令
分别是节目加,节目减,音量加,音量减四个具体命令。
public class AddItemCommand implements Command{
// 持有一个接收者对象的引用
private ChangeReceiver mChangeReceiver;
public AddItemCommand(ChangeReceiver changeReceiver){
this.mChangeReceiver=changeReceiver;
}
@Override
public void execute() {
// 调用遥控器的具体方法执行操作
mChangeReceiver.addItem();
}
}
public class SubtractItemCommand implements Command{
// 持有一个接收者对象的引用
private ChangeReceiver mChangeReceiver;
public SubtractItemCommand(ChangeReceiver changeReceiver){
this.mChangeReceiver=changeReceiver;
}
@Override
public void execute() {
// 调用遥控器的具体方法执行操作
mChangeReceiver.subtractItem();
}
}
public class AddVoiceCommand implements Command{
// 持有一个接收者对象的引用
private ChangeReceiver mChangeReceiver;
public AddVoiceCommand(ChangeReceiver changeReceiver){
this.mChangeReceiver=changeReceiver;
}
@Override
public void execute() {
// 调用遥控器的具体方法执行操作
mChangeReceiver.addVoice();
}
}
public class SubtractVoiceCommand implements Command{
// 持有一个接收者对象的引用
private ChangeReceiver mChangeReceiver;
public SubtractVoiceCommand(ChangeReceiver changeReceiver){
this.mChangeReceiver=changeReceiver;
}
@Override
public void execute() {
// 调用遥控器的具体方法执行操作
mChangeReceiver.subtractVoice();
}
}
- 组装遥控器
把四个命令按键安装到遥控器上,相当于Invoker,请求者角色。
public class RemoteControler {
private AddItemCommand mAddItemCommand; // 节目加命令对象的引用
private SubtractItemCommand mSubtractItemCommand; // 节目减命令的引用
private AddVoiceCommand mAddVoiceCommand; // 声音加命令的引用
private SubtractVoiceCommand mSubtractVoiceCommand; // 声音减命令的引用
public void setAddItemCommand(AddItemCommand addItemCommand) {
mAddItemCommand = addItemCommand;
}
public void setSubtractItemCommand(SubtractItemCommand subtractItemCommand) {
mSubtractItemCommand = subtractItemCommand;
}
public void setAddVoiceCommand(AddVoiceCommand addVoiceCommand) {
mAddVoiceCommand = addVoiceCommand;
}
public void setSubtractVoiceCommand(SubtractVoiceCommand subtractVoiceCommand) {
mSubtractVoiceCommand = subtractVoiceCommand;
}
/**
* 遥控器上的节目加按键
*/
public void addItem(){
mAddItemCommand.execute();
}
/**
* 遥控器上的节目减按键
*/
public void subtractItem(){
mSubtractItemCommand.execute();
}
/**
* 遥控器上的声音加按键
*/
public void addVoice(){
mAddVoiceCommand.execute();
}
/**
* 遥控器上的声音减按键
*/
public void subtractVoice(){
mSubtractVoiceCommand.execute();
}
}
- 客户端代码
// 首先要有一个接收者对象
ChangeReceiver changeReceiver=new ChangeReceiver();
// 构造四个命令
AddItemCommand addItemCommand=new AddItemCommand(changeReceiver);
SubtractItemCommand subtractItemCommand=new SubtractItemCommand(changeReceiver);
AddVoiceCommand addVoiceCommand=new AddVoiceCommand(changeReceiver);
SubtractVoiceCommand subtractVoiceCommand=new SubtractVoiceCommand(changeReceiver);
// 组装遥控器,把代表不同命令的按键组装到遥控器上
RemoteControler remoteControler=new RemoteControler();
remoteControler.setAddItemCommand(addItemCommand);
remoteControler.setSubtractItemCommand(subtractItemCommand);
remoteControler.setAddVoiceCommand(addVoiceCommand);
remoteControler.setSubtractVoiceCommand(subtractVoiceCommand);
// 我们可以愉快地通过遥控器对电视发出遥控指令了
remoteControler.addItem();
remoteControler.subtractItem();
remoteControler.addVoice();
remoteControler.subtractVoice();
四 优缺点
优点
- 类间解耦
请求者与接收者之间没有任何依赖关系,请求者实现功能只需调用Command中的execute方法即可,不需要了解底层是哪个接收者。 - 可扩展性
Command具体的类可以非常容易扩展。
缺点
如果Command比较多,会造成类数目的膨胀。所以在实际开发中要不要采用命令模式还需要斟酌。
作者:Jackson杰
转自链接:https://www.jianshu.com/p/aa3e2fbe503b
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。