命令(Command)模式
2016-11-05 本文已影响61人
_时光念你
一 前言
离开具体业务需求谈设计模式都是耍流氓,OOP的世界里出现设计模式是为了让程序更有弹性,易于扩展。
而且经过这么多年的发展,前辈们从具体的业务需求抽象出很多种的设计模式,这次我们就来探讨一下其中之命令(Command)模式,代码用例是Java语言。
二 需求场景#
假设现在有这样一个需求:我们公司接到一个订单,要求生产一个电器遥控器,要求每次按右边的ON/OFF按钮,左边对应的插槽上的电器会响应该命令,而且厂家已经提供了所有的电器的使用接口,重要的是要考虑左边的插槽对应的电器以后可能会换成其他的电器,按下最下面的撤销按钮会执行与上次命令相反的命令,比如上次ON->撤销就是OFF,遥控器如图:
遥控器.png厂家给的电器接口如下:
// 电灯的接口
public void on(); // 开灯
public void off();// 关灯
// 电视的接口
public void onTelevision(); // 开电视
public void offTelevision();// 关电视
// 还有其他各种电器...
还有其他的电器接口,但是这些接口必定有开和关两个基本,接口的名字可能是不一样的,因为我们不可能让厂家修改接口名称。呃...毕竟顾客就是上帝!
三 一般的实现思路
按照一般的思维逻辑我们可能这么写:
// 伪代码
// 遥控器
public class RemoteController{
// 第i个按钮的on被点击
public void onButtonWhenPush(int index){
1.先找到对应i的位置的电器
2.判断对应的电器的类型,因为每个不同的电器的接口方法不是一样的,所以需要强制类型转换一下
3.获得电器类型,执行该电器的开方法,比如电视的话执行onTelevision(),电灯执行on(),其他电器类似
}
// 第i个按钮的off被点击
public void offButtonWhenPush(int index){
// 跟onButtonWhenPush方法的实现逻辑类似
}
}
对了,还有一个撤销按钮没有实现,我们可以定义一个变量来记录刚刚执行命令的电器,并且每个电器类都要有一个记录电器状态的boolean值,如果这样写的,厂商提供的接口就会被我们改变,这当然不是我们想要的设计.如果我们能将每次电器执行的操作封装成一个对象,那会怎么样呢?
引入今天的主角-命令模式,先看看定义:
命令模式 将请求封装成"对象",以便使用不同的请求、队列、或者日志来参数化其他对象.命令模式也支持可撤销的操作.
四 命令模式实现
电器:
/// 电灯类
public class Light {
public void on(){
System.out.println("Light - ON");
}
public void off(){
System.out.println("Light - OFF");
}
}
/// 电视类
public class Television {
public void onTelevision(){
System.out.println("Television - ON");
}
public void offTelevision(){
System.out.println("Television - OFF");
}
}
命令接口:
/// 命令接口
public interface Command {
// 执行命令
public void execute();
// 撤销
public void undo();
}
电灯命令类(电视类也是差不多的,厂商给的什么接口就写什么接口):
/// 开灯命令
public class LightOnCommand implements Command{
Light light;
LightOnCommand(Light light){
this.light = light;
}
public void execute(){
light.on();
}
public void undo(){
light.off();
}
}
/// 关灯命令
public class LightOffCommand implements Command{
Light light;
LightOffCommand(Light light){
this.light = light;
}
public void execute(){
light.off();
}
public void undo(){
light.on();
}
}
空命令(这也是一种设计模式):
public class NullCommand implements Command{
public void execute(){
System.out.println("空指令被执行");
}
public void undo(){
System.out.println("撤销了空指令");
}
}
遥控器:
/// 遥控器
public class RemoteController {
public Command undoCommand; // 上一次指令,用来执行undo
public static final int componentCount = 5;
Command[] onCommands;
Command[] offCommands;
public RemoteController()
{
this.onCommands = new Command[componentCount];
this.offCommands = new Command[componentCount];
// 空命令也是一种设计模式
NullCommand nc = new NullCommand();
for(int i = 0;i < componentCount;++i){
this.onCommands[i] = nc;
this.offCommands[i] = nc;
}
}
/**
* 设置对应插槽的命令
**/
public void setCommand(int index,Command onCommand,Command offCommand ){
onCommands[index] = onCommand;
offCommands[index] = offCommand;
}
/**
* 打开
**/
public void onButtonPushed(int index){
onCommands[index].execute();
undoCommand = onCommands[index];
}
/**
* 关闭
**/
public void offButtonPushed(int index){
offCommands[index].execute();
undoCommand = offCommands[index];
}
/**
* 撤销
**/
public void undoButtonPushed(){
undoCommand.undo();
}
}
现在来进行测试:
public class CommandDesignPattern {
public static void main(String[] args)
{
// 电器
Light light1 = new Light();
Light light2 = new Light();
Television tv1 = new Television();
Television tv2 = new Television();
// 开命令
LightOnCommand lightOnCommand1 = new LightOnCommand(light1);
LightOnCommand lightOnCommand2 = new LightOnCommand(light2);
TelevisionOnCommand televisionOnCommand1 = new TelevisionOnCommand(tv1);
TelevisionOnCommand televisionOnCommand2 = new TelevisionOnCommand(tv2);
// 空命令
NullCommand nullCommand = new NullCommand();
// 关命令
LightOffCommand lightOffCommand1 = new LightOffCommand(light1);
LightOffCommand lightOffCommand2 = new LightOffCommand(light2);
TelevisionOffCommand televisionOffCommand1 = new TelevisionOffCommand(tv1);
TelevisionOffCommand televisionOffCommand2 = new TelevisionOffCommand(tv2);
// 设置遥控器对应插槽的命令
RemoteController remoteController = new RemoteController();
remoteController.setCommand(0, lightOnCommand1, lightOffCommand1);
remoteController.setCommand(1, lightOnCommand2, lightOffCommand2);
remoteController.setCommand(2, nullCommand, nullCommand);
remoteController.setCommand(3, televisionOnCommand1, televisionOffCommand1);
remoteController.setCommand(4, televisionOnCommand2, televisionOffCommand2);
// 测试遥控器
remoteController.onButtonPushed(0); // 打开槽1的灯
remoteController.offButtonPushed(0); // 关闭槽1的灯
remoteController.onButtonPushed(3); // 打开槽4的电视
remoteController.offButtonPushed(3); // 关闭槽4的电视
remoteController.undoButtonPushed();// 撤销上一次操作
}
}
执行结果:
Light - ON
Light - OFF
Television - ON
Television - OFF
Television - ON
遥控器流程图.png
参考自:<<Head First设计模式>>