行为型设计模式之命令模式
解释
命令模式顾名思义就是
对命令进行封装,将一个个命令抽出来变成对象,使调用命令者和实现命令者之间达到松耦合
意义
- 解耦
- 易扩展
- 组合命令
- 命令的记录
举例
不使用命令模式
例子解决一切,我们来说一个通过遥控器控制电视机的案例
角色
Invoker 调用者(遥控器)
Receiver 实现者(电视)
Client 来实现效果的类(我们)
Achievable 功能接口(开电源,换台,关电源)
代码
Achievable
public interface Achievable {
void open();
void close();
void next(int channel);
}
Receiver
public class Receiver implements Achievable {
@Override
public void open() {
System.out.println("开机");
}
@Override
public void close() {
System.out.println("关机");
}
@Override
public void next(int channel) {
System.out.println("换台" + channel);
}
}
Invoker
public class Invoker implements Achievable{
private Receiver receiver;
public void setReceiver(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void open() {
receiver.open();
}
@Override
public void close() {
receiver.close();
}
@Override
public void next(int channel) {
receiver.next(channel);
}
}
操控
public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
invoker.setReceiver(new Receiver());
invoker.open();
invoker.next(1);
invoker.close();
}
}
结果
开机
换台1
关机
意外发现
本来没打算使用设计模式,定睛一看,这就是个代理模式。。先不管代理模式,有人说,遥控器多此一举,直接
public class Client {
public static void main(String[] args) {
Receiver receiver=new Receiver();
receiver.open();
receiver.next(1);
receiver.close();
}
}
万事大吉,回家睡觉
仔细想一下,你为啥要遥控器?
- 电视太远了,够不到
- 电视太贵了,坏了还得买电视
对应着
- 电视对象你拿不到
- 电视对象你不能操作(安全性)
那就说我使用代理模式,你总没脾气了吧,我说的是代理可以,但是无法满足我的需求,我们学习的是命令模式,还需要一些其他的骚操作
使用命令模式实现组合命令
角色
Invoker 调用者(遥控器)
Receiver 实现者(电视)
Client 来实现效果的类(我们)
Achievable 功能接口(开电源,换台,关电源)
(增加了)
Command 命令抽象接口
CloseCommand、NextChannelCommand、OpenCommand 具体实现命令
可以看出,命令模式将命令抽取成了对象
代码
Command
(可以是接口也可以是类,我这里是为了传值,所以用的抽象类还额外传递了Receiver,接口中通过setReceiver注入Receiver效果也一样)
public abstract class Command {
protected Receiver receiver = new Receiver();
public abstract void execute();
}
Command多种命令实现类
public class CloseCommand extends Command {
@Override
public void execute() {
receiver.close();
}
}
public class NextChannelCommand extends Command {
private int current = 0;
public NextChannelCommand setChannel(int channel) {
current = channel;
return this;
}
@Override
public void execute() {
receiver.next(current);
}
}
public class OpenCommand extends Command {
@Override
public void execute() {
receiver.open();
}
}
Invoker
public class Invoker {
private List<Command> commands = new ArrayList<>();
public void add(Command command) {
commands.add(command);
}
public void remove(Command command) {
commands.remove(command);
}
public void execute() {
for (Command c : commands) {
c.execute();
}
}
}
Receiver不变化
实现
public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
invoker.add(new OpenCommand());
invoker.add(new NextChannelCommand().setChannel(2));
invoker.add(new NextChannelCommand().setChannel(3));
invoker.add(new CloseCommand());
invoker.execute();
}
}
结果
开机
换台2
换台3
关机
意外发现
说到组合命令,模版模式也可以实现组合命令,是在父类final方法中调用了其他的方法,子类实现具体操作,也可以实现命令的组合模式
想一想和命令模式区别
- 模版模式下 组合的命令固定,如果想要修改想要修改父类或者在父类创建新的方法
- 命令模式下 根据命令需要可以实现不同的命令组合,且不用修改父类的方法
不光如此,我们看到了,因为我们把命令生命成了对象,所以我们可以去存储他,我们又可以做到
- 命令的恢复(返回功能)
- 命令的存储(日志存储等)
还需要注意的是,我们调用方法实现命令的时候,全都是通过execute()方法执行的,对外隐藏了内部实现
命令模式实现返回
其他类不变
Invoker
public class Invoker {
private List<Command> commands = new ArrayList<>();
public void action(Command command) {
command.execute();
commands.add(command);
}
public void back() {
if (commands.size() < 2) {
return;
}
System.out.print("---返回---");
commands.remove(commands.size() - 2).execute();
}
public void getInfo() {
for (Command c : commands) {
System.out.println(c);
}
}
}
实现
public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
invoker.action(new OpenCommand());
invoker.action(new NextChannelCommand().setChannel(2));
invoker.action(new NextChannelCommand().setChannel(3));
invoker.action(new NextChannelCommand().setChannel(1));
invoker.back();
invoker.back();
invoker.action(new CloseCommand());
invoker.getInfo();
}
}
结果
开机
换台2
换台3
换台1
---返回---换台3
---返回---换台2
关机
bytetrade.io.zyhang.command.OpenCommand@14ae5a5
bytetrade.io.zyhang.command.NextChannelCommand@7f31245a
bytetrade.io.zyhang.command.CloseCommand@6d6f6e28
总结使用范围
命令模式适用于
- 需要对行为进行处理,存储,恢复,管理
- 多种行为的自由组合
不足
- 容易类爆炸
- 修改时比直接引用实现类略微繁琐
使用与否
功能简单没必要如此麻烦,设计模式本来就是为了解决问题,优化项目结构所提出的方案,至于解决问题所带来的负面效果就需要自己取舍了,符合自己需求才是最合适的解决方案,不要为了设计而设计