首先是简单版本的设计模式:
命令模式:将请求封装成对象,以便使用不同的请求、日志、队列等来参数化其他对象。命令模式也支持撤销操作。
案例:
某个公司需要设计一个多用功能的遥控器。基本的需求如下:
该遥控器有可以控制风扇,白炽灯,热水器等等的多对开关,而且可能还有其他的电器,暂时不做其功能,但是希望可以保留接口,用的时间可以方便的扩展。
除上面的需求之外,还需要有个按钮,可以撤销上一步的操作。基本功能如下图:
在设计遥控器时,风扇,白炽灯,热水器的开关方法已经定义好,其名字各不相同。不妨设置其方法为如下:单拿灯做例子
package domain.commandpattern;
//厂商类
public class Light {
public void on(){
System.out.println("开灯啦");
}
public void off(){
System.out.println("关灯啦");
}
}
设计思路如图
package domain.commandpattern;
//抽象的Command接口
public interface Command {
//命令的执行方法
public void execute();
//命令的回撤方法
public void undo();
}
把开灯关灯做成命令对象
package domain.commandpattern;
public class LightOffCommand implements Command {
private Light light;
@Override
public void execute() {
light.off();
}
@Override
public void undo() {
light.on();
}
public LightOffCommand() {
super();
}
public LightOffCommand(Light light) {
super();
this.light = light;
}
}
package domain.commandpattern;
public class LightOnCommand implements Command {
private Light light;
@Override
public void execute() {
light.on();
}
@Override
public void undo() {
light.off();
}
public LightOnCommand() {
super();
}
public LightOnCommand(Light light) {
super();
this.light = light;
}
}
package domain.commandpattern;
//在未指定遥控器按钮功能时,将此作为默认
public class UnknownCommand implements Command {
@Override
public void execute() {
System.out.println("未指定功能,無法執行");
}
@Override
public void undo() {
System.out.println("未指定功能,無法撤銷");
}
}
遥控器类
package domain.commandpattern;
import java.util.Stack;
public class RemoteControl {
private Command[] oncommands;
private Command[] offcommands;
private Stack<Command> previousCommand =new Stack<Command>();
//默认遥控器按钮为7
private int DEFAULT_Button_NUM = 7;
//当遥控器构造出来时就把几个按钮设置成无命令的按钮
//未指定按7按钮构造,指定了数目就按指定数目构造
public RemoteControl(){
oncommands = new Command[DEFAULT_Button_NUM];
offcommands = new Command[DEFAULT_Button_NUM];
UnknownCommand unknownCommand = new UnknownCommand();
for (int i = 0; i < DEFAULT_Button_NUM; i++) {
oncommands[i] = unknownCommand;
offcommands[i] = unknownCommand;
}
}
public RemoteControl(int num) {
oncommands = new Command[num];
offcommands = new Command[num];
UnknownCommand unknownCommand = new UnknownCommand();
for (int i = 0; i < num; i++) {
oncommands[i] = unknownCommand;
offcommands[i] = unknownCommand;
}
}
public void setCommand(int index , Command oncommand , Command offcommand){
oncommands[index] = oncommand;
offcommands[index] = offcommand;
}
public void pressLeft(int index){
oncommands[index].execute();
previousCommand.push(oncommands[index]);
}
public void pressRight(int index){
offcommands[index].execute();
previousCommand.push(offcommands[index]);
}
public void undo(){
if(previousCommand.isEmpty()){
System.out.println("當前沒有任何命令被執行過");
}else{
previousCommand.pop().undo();
}
}
}
最后测试一下:
package testmethod.commandpattern;
import domain.commandpattern.Light;
import domain.commandpattern.LightOffCommand;
import domain.commandpattern.LightOnCommand;
import domain.commandpattern.RemoteControl;
public class TestCommandPattern {
public static void main(String[] args) {
//现在搞个遥控器,新买的--new的
RemoteControl remoteControl = new RemoteControl(10);
//厂商类,就是电灯,空调,音响,冰箱等等提供功能的类
Light light = new Light();
//有关灯开和关的两个指令
LightOnCommand lightOnCommand = new LightOnCommand(light);
LightOffCommand lightOffCommand = new LightOffCommand(light);
//把两个指令设定到遥控器指定位置
remoteControl.setCommand(0, lightOnCommand,lightOffCommand);
System.out.println("------------过了一千年-------------");
//有个人按了这款遥控器的按钮,0行左边按钮对应灯开指令1行左边按钮对应灯关指令
remoteControl.pressLeft(0);
remoteControl.pressRight(0);
remoteControl.undo();
remoteControl.undo();
}
}
结果:
这是单个命令单个实现,也可以进行命令组合,多个命令一起执行,这个也很好设计
package domain.commandpattern;
public class CombineCommand implements Command {
private Command[] allCommands;//没考虑具体细节,这个类就大概这么个意思
@Override
public void execute() {
if(allCommands!=null && allCommands.length>0){
for (int i = 0; i < allCommands.length; i++) {
allCommands[i].execute();
}
}
}
@Override
public void undo() {
if(allCommands!=null && allCommands.length>0){
for (int i = 0; i < allCommands.length; i++) {
allCommands[i].undo();
}
}
}
}
在Test类中,进行一个组装,把要一起执行的命令都放入到CombineCommand中,然后把CombineCommand整个作为一个键放到遥控器上,就实现了多个命令组合完成的效果