内容抄自《设计模式》清华大学出版社,2011
命令模式的动机与定义: 命令模式将请求的发送者和接收者解耦,在发送者与接收者之间引入命令对象,将发送者的
请求封装在命令对象中,再通过命令对象来调用接收者的方法。
命令模式的动机:
命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何
发送请求,而不必知道如何完成请求,例如开关和电灯,开关是请求的发送者,而电灯是请求的接收者,它们之间并
不存在直接的耦合关系,而是通过电线连接到一起,开关并不需要知道如何将请求传输给电灯,而是通过电线来完成
这项功能,可以理解为在电线中封装了开灯或者关灯请求,此时电线充当了封装请求的命令对象,不同的电线可以连
接不同的请求接收者,因此只需要更换一根电线,相同的开关即可以操纵不同的电器设备。
模式定义:
将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持
可撤销的操作,其别名为动作(Action)模式或 事务(Transaction)模式。
结构分析:
包含角色:
1.Command(抽象命令类)
2.ConcreteCommand(具体命令类)
3.Invoke(调用者)
4.Receiver(接收者)
模式分析:
1.Command
public interface Command{
public void exec();
}
2.ConcreteCommand
public class ConcreteCommand implements Command{
private Receiver receiver;
@Overrides
public void exec(){
receiver.action();
}
}
3.Invoke
public class Invoke{
private Command command;
public void call(){
command.exec();
}
}
4.Receiver
public void Receiver{
public void action(){};
}
优点:
1.将请求者与接收者解耦,相同的请求者可以对应不同的接收者,相同的接收者也可以供不同的请求者使用,(这就是为什么不能省略接收者的原因)
两者具有良好的独立性。
2.新的命令不需要修改源代码,符合开闭
3.可以实现命令队列和组合命令,实现批处理操作
4.可以实现Undo和Redo操作
缺点: 会导致过多的具体命令类
适用环境:
1.系统需要请求者与接收者解耦,使得调用者和接收者相互独立。
2.系统需要在不同的时间指定请求,将请求排队和执行请求。
3.系统需要支持Undo和Redo
4.系统需要将一组操作组合在一起,即支持宏命令,实现命令的批处理。
扩展:
1.Undo和Redo
2.命令组合
栗子:非命令模式
public class WithoutOrder {
//起源
//没有任何东西,没有开关,开关空调直接拔插头,新的命令需要修改源代码
public static void main1(String[] args) {
AirCondition airCondition = new AirCondition();
airCondition.open();
airCondition.close();
}
//second
//加入了开关控制,存在强耦合问题,如果要变换接收者,不抽象无法变更
public static void main2(String[] args) {
Controller controller = new Controller();
controller.setReceiver(new AirCondition());
controller.call();
}
static class Controller{
//接收者
private AirCondition receiver;
public AirCondition getReceiver() {
return receiver;
}
public void setReceiver(AirCondition receiver) {
this.receiver = receiver;
}
//请求
public void call(){
//现在是强耦合,看上去好像没问题
//问题描述1:如果加入业务逻辑,比如,当室内温度小于25度时不开启空调,那么要怎么写呢
//问题描述2:如果加入业务逻辑,比如,当没有脏衣服的时候不运行洗衣机
//问题描述3: xxxxx ~~~ 问题描述n
// if(receiver instanceof AirCondition){
// if(当前温度大于等于25度){
// receiver.show();
// }
// }
// else if(receiver instanceof WashingMachine){
// if(有脏衣服){
// receiver.show();
// }
// }
//.....这里写了n多的业务逻辑判断,每调用一次方法就进行n多次判断,添加新的接收者还要修改源代码
receiver.open();
}
}
//接收者
static class AirCondition{
public void open() {
System.out.println("空调开了");
}
public void close() {
System.out.println("空调关了");
}
}
}
栗子:命令模式
public class WithOrder {
//调用者
static class Controller{
//不关联接收者了,现在关联命令
private Commond commond;
public Commond getCommond() {
return commond;
}
public void setCommond(Commond commond) {
this.commond = commond;
}
public void call(){
//没有任何业务逻辑,逻辑已经包含在具体命令中
commond.exec();
}
}
//接收者
static class AirCondition{
public void open() {
System.out.println("空调开了");
}
public void close() {
System.out.println("空调关了");
}
}
//抽象命令类
static interface Commond{
public void exec();
}
//具体命令,开空调
static class OpenAirCondition implements Commond{
private AirCondition receiver;
public OpenAirCondition() {
this.receiver = new AirCondition();
}
@Override
public void exec() {
//if(当前室内温度大于25度){
receiver.open();
//}
}
}
//具体命令,关空调
static class CloseAirCondition implements Commond{
private AirCondition receiver;
public CloseAirCondition() {
this.receiver = new AirCondition();
}
@Override
public void exec() {
//if(当前室内温度小于25度){
receiver.close();
//}
}
}
public static void main(String[] args) {
Controller controller = new Controller();
controller.setCommond(new OpenAirCondition());
controller.call();
controller.setCommond(new CloseAirCondition());
controller.call();
}
}