设计模式之命令模式
前言
假设,小明去一个餐厅吃饭,首先,他会把服务员叫过来,告诉服务员自己想要吃什么,服务员将小明创建的订单拿到后台窗口,告诉厨师,订单来了,厨师看到订单之后,就开始做相应的食物。
这是一个很常见的生活细节,那么问题来了,为什么小明不直接去跟厨师打交道,直接告诉厨师自己需要什么呢?因为有这样几个问题:
- 小明并不知道厨师在哪儿
- 小明找到厨师之后会一个不小心了解到了一些不该看到的后台场景(比如:脏、乱、差)
- 但很多人人都来找厨师的时候,会把后台弄得很乱
- 如果新增加小明以前从来没有接触过的厨师,那估计又得有很多麻烦了
- 。。。。
那么,这些问题的关键在于什么?关键在于小明的发出的请求(即动作的请求者)和厨师完成小明的请求(即动作的执行者)之间有很复杂的关系,这就是耦合性很高,因此产生了很多问题。
因此,在实际生活中,中间是有服务员的,服务员的角色就将小明(动作的请求者)和厨师(动作的执行者)进行了完全解耦。小明只需要将自己想要的订单告诉服务员(createOrder),他并不关心具体是怎么做的,服务员拿到订单后(takeOrder)就告诉厨师有订单来了(orderUp),然后厨师并不关注是谁点了这些吃的,他只负责做就行了。其中,服务员就相当于命令的管理者。
实现这样的命令模式
依据我们上面的分析,我们得到一下几个元素:
- 谁使用遥控器 —> 用户(Client)
- 谁执行遥控器的命令:来自厂商的具体家电的操作的类 —> 厨师(Receiver)
- 谁来管理这些命令:遥控器本身 —> 服务员(Waiter)
- 由用户传递给遥控器,再由遥控器传递给具体的家电之间的信号 —> 命令(Command)
首先分析动作请求者合动作执行者之间传递的命令
客户告诉服务员,服务员告诉厨师,她们只做了一件事,那就是执行这个命令,只是服务员执行命令是orderUp,即通知厨师,厨师收到命令之后,就做他该做的事了,所以,在命令里面,只需要包含一个执行的方法即可:
public interface Command {
public void execute();
}
在具体的命令中,比如开灯命令,因为在这个命令里面的execute会将执行权交给最终执行者,即具体的家电类,所以,在具体命令的实现中,需要引用相应的具体的家电类:
public class LightOnCommand implements Command {
Light light;
public LightOnCommand(Light light){
this.light = light;
}
public void execute() {
light.on();
}
}
最终执行开灯的是Light这个类。到这里,一个开灯的命令就写好了,而且该命令已经关联了具体的动作执行者。但是,具体执行者是Light,我们还没有Light这个家电的具体操作类(即厨师),所以添加Light的具体操作(厨师做食物的具体方法):
public class Light {
private String where = "";
public Light(String where){
this.where = where;
}
public void on(){
System.out.println(where+"灯开了 ");
}
}
其中的where成员变量只是为了表示是哪里的灯,在此处做讲解阔以完全去掉where变量。到目前位置,我们已经完成了上述第二个合第三个任务了,接下来,就需要关联上动作的申请者。但是,我们知道,仅仅一个命令是不能直接被调用的,它必须衣服在一个管理这些命令的对象上,这个时候就是遥控器这个类出场了。
再分析这些命令的管理者:遥控器
单独的命令是无法对上用户请求的,用户下单之后没用服务员,是无法告知厨师进行执行命令的。所以,需要由服务员来完成命令的装配操作,服务员需要一方面提供给顾客进行下单的接口,还得将这个命令告诉厨师。
通过分析,在遥控器这样的对象中一定引用一个命令,而且还需要将用户的想要开灯的命令(体现在用户选择按开灯按钮,但是还没按)变现在遥控器当中,即将遥控器中的命令设置为开灯命令(现在就等用户按下去了),并且还需要将来自用户的操作(比如按下遥控器的按钮)转变为命令并且让改命令的执行者(即相应的家电,在餐厅例子中就是厨师&#x