目的:任何模式的出现,都是为了解决一些特定的场景的耦合问题,以达到对修改封闭,对扩展开放的效果。命令模式也不例外,命令模式是为了解决命令的请求者和命令的实现者之间的耦合关系。
解决了这种耦合的好处我认为主要有两点:
1.更方便的对命令进行扩展(注意:这不是主要的优势,后面会提到)
2.对多个命令的统一控制(这种控制包括但不限于:队列、撤销/恢复、记录日志等等)
模式解析:经典的命令模式包括4个角色:
Command:定义命令的统一接口
ConcreteCommand:Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。
Receiver:命令的实际执行者
Invoker:命令的请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。
下面对上面四个角色的经典实现用代码来进行说明,这也是大部分文章对命令模式的运用方式。
需求:通过遥控器对灯泡进行开关操作,在设计遥控器时,白炽灯的开关方法已经定义好,并且,我们希望还能实现松耦合。
为了实现松耦合,我们现在来想一下,周末去请朋友吃饭,服务员mm问你吃什么,你说水煮活鱼,然后在菜单上面,写上水煮活鱼。下个星期天想吃花生米啤酒,同样也写在订单上,然后服务员mm把订单拿给厨师。
在上面的例子中,无论你点了什么菜,服务员mm,只需要知道顾客点的什么菜,从而给不同的厨师做(虽然不是直接的,但最终凉菜会给凉菜的师傅做,热菜的会给热菜的厨师做),然而具体的怎么做是厨师的事情,服务员知道顾客点上面菜,只是为了能正确的交个厨师去做。
其实在这个例子中,也是一个命令模式的例子,不同的订单对应的有不同的厨师,最终订单拿到厨师面前,就是对厨师下了个命令,要做菜了。每订单或者说是每种菜都对应着自己的厨师,所以,客服需要有订单的的引用,订单为了知道调用哪个厨师,需要有厨师引用;两个引用都是使用的组合。从而可以调用多种自己需要对象的方法来实现松耦合。这里记住:客服mm知道顾客点菜的目的是为了让不同的厨师去做。再直接一些就是为了使用不同的命令。
上面的吃饭问题和我们的遥控器问题差不多,都是包含下命令,命令的执行者,以及命令的具体内容。
代码实现:
//command:命令接口类
public interface Command {
public void excute();
}
//command接口实现类
//设置专门的类来管理命令,实现功能只需要调用该类的执行即可
public class LigthtOnCommand implements Command {
Light light;
public LigthtOnCommand(Light light) {
this.light = light;
}
@Override
public void excute() {
light.on();
}
}
//Invoker:请求命令
public class SimpleRemoteControl {
Command command;
public Command setCommand(Command command) {
this.command = command;
return command;
}
public void buttonWasPress() {
command.excute();
}
}
//Receiver:执行命令
//测试类
public class Test {
public static void main(String[] args) {
Light light = new Light();
LigthtOnCommand command2 = new LigthtOnCommand(light);
SimpleRemoteControl control2 = new SimpleRemoteControl();
control2.setCommand(command2);
control2.buttonWasPress();
}
}