继续设计模式哈,今天带来命令模式,二话不说,先看定义:
定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
这尼玛定义,看得人蛋疼,看不明白要淡定,我稍微简化一下:将请求封装成对象,将动作请求者和动作执行者解耦。好了,直接用例子来说明。
需求:最近智能家电很火热啊,未来尼玛估计冰箱都会用支付宝自动买东西了,,,,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
这个需求一看,尼玛要是没有什么个性化、扩展性还好说啊,直接针对每个遥控器的按钮onClick,然后在里面把代码写死就搞定了,但是个性化怎么整,还要有扩展性。。。
好了,下面命令模式出场,命令模式的核心就是把命令封装成类,对于命令执行者不需要知道现在执行的具体是什么命令。
1、首先看下我们拥有的家电的API:
package com.zhy.pattern.command;
/**
* 门
* @author zhy
*
*/
public class Door
{
public void open()
{
System.out.println("打开门");
}
public void close()
{
System.out.println("关闭门");
}
}
package com.zhy.pattern.command;
/**
* 电灯
* @author zhy
*
*/
public class Light
{
public void on()
{
System.out.println("打开电灯");
}
public void off()
{
System.out.println("关闭电灯");
}
}
package com.zhy.pattern.command;
/**
* 电脑
* @author zhy
*
*/
public class Computer
{
public void on()
{
System.out.println("打开电脑");
}
public void off()
{
System.out.println("关闭电脑");
}
}
看来我们有电灯、电脑、和门,并且开关的接口的设计好了。接下来看如何把命令封装成类:
package com.zhy.pattern.command;
public interface Command
{
public void execute();
}
package com.zhy.pattern.command;
/**
* 关闭电灯的命令
* @author zhy
*
*/
public class LightOffCommond implements Command
{
private Light light ;
public LightOffCommond(Light light)
{
this.light = light;
}
@Override
public void execute()
{
light.off();
}
}
package com.zhy.pattern.command;
/**
* 打开电灯的命令
* @author zhy
*
*/
public class LightOnCommond implements Command
{
private Light light ;
public LightOnCommond(Light light)
{
this.light = light;
}
@Override
public void execute()
{
light.on();
}
}
package com.zhy.pattern.command;
/**
* 开电脑的命令
* @author zhy
*
*/
public class ComputerOnCommond implements Command
{
private Computer computer ;
public ComputerOnCommond( Computer computer)
{
this.computer = computer;
}
@Override
public void execute()
{
computer.on();
}
}
package com.zhy.pattern.command;
/**
* 关电脑的命令
* @author zhy
*
*/
public class ComputerOffCommond implements Command
{
private Computer computer ;
public ComputerOffCommond( Computer computer)
{
this.computer = computer;
}
@Override
public void execute()
{
computer.off();
}
}
好了,不贴那么多了,既然有很多命令,按照设计原则,我们肯定有个超类型的Command,然后各个子类,看我们把每个命令(请求)都封装成类了。接下来看我们的遥控器。
package com.zhy.pattern.command;
/**
* 控制器面板,一共有9个按钮
*
* @author zhy
*
*/
public class ControlPanel
{
private static final int CONTROL_SIZE = 9;
private Command[] commands;
public ControlPanel()
{
commands = new Command[CONTROL_SIZE];
/**
* 初始化所有按钮指向空对象
*/
for (int i = 0; i < CONTROL_SIZE; i++)
{
commands[i] = new NoCommand();
}
}
/**
* 设置每个按钮对应的命令
* @param index
* @param command
*/
public void setCommand(int index, Command command)
{
commands[index] = command;
}
/**
* 模拟点击按钮
* @param index
*/
public void keyPressed(int index)
{
commands[index].execute();
}
}
package com.zhy.pattern.command;
/**
* @author zhy
*
*/
public class NoCommand implements Command
{
@Override
public void execute()
{
}
}
注意看到我们的遥控器有9个按钮,提供了设置每个按钮的功能和点击的方法,还有注意到我们使用了一个NoCommand对象,叫做空对象,这个对象的好处就是,我们不用执行前都判断个if(!=null),并且提供了一致的操作。
最后测试一下代码:
package com.zhy.pattern.command;
public class Test
{
public static void main(String[] args)
{
/**
* 三个家电
*/
Light light = new Light();
Door door = new Door();
Computer computer = new Computer();
/**
* 一个控制器,假设是我们的app主界面
*/
Co