设计模式:命令模式

  命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

  下面我们利用一个场景来进行理解理解

  场景:有一个遥控器,可以控制电灯、音响的开关,遥控器发出一个打开或关闭电灯或音响的请求,这个请求被我们封装成了命令对象。然后将命令对象传给接受者(即电灯或音响),接受者就可以执行命令了。

   下面我们就来看看代码的实现。首先我们先创建几个装置类对象

//装置电灯
public class Light {
    public void on(){
        System.out.println("Light ON");
    }
    
    public void off(){
        System.out.println("Light OFF");
    }
}

//装置音响
public class Stereo {
    public void on(){
        System.out.println("Stereo ON");
    }
    
    public void off(){
        System.out.println("Stereo OFF");
    }
    
    public void setCD(){
        System.out.println("Stereo set a CD");
    }
    
    public void setVolume(){
        System.out.println("Stereo set volume 11");
    }
}

  接着我们创建一个命令对象的接口,并创建各种装置的具体命令

//创建一个命令对象的接口,所以命令都实现此接口
public interface Command {
    //只需一个方法
    public void execute();
}

//命令对象--开灯命令
public class LightOnCommand implements Command{
    Light light;
    
    public LightOnCommand(Light light){
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.on();
    }
}

//命令对象--关灯命令
public class LightOffCommand implements Command{
    Light light;
    
    public LightOffCommand(Light light){
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.off();
    }
}

//命令对象--打开音响命令
public class StereoOnCommand implements Command {
    Stereo stereo;
    
    public StereoOnCommand(Stereo stereo){
        this.stereo = stereo;
    }
    @Override
    public void execute() {
        stereo.on();
        stereo.setCD();
        stereo.setVolume();
    }
}

//命令对象--关闭音响命令
public class StereoOffCommand implements Command{
    Stereo stereo;
    
    public StereoOffCommand(Stereo stereo){
        this.stereo = stereo;
    }
    @Override
    public void execute() {
        stereo.off();
    }
}

  当然,少不了遥控器对象了

//遥控器对象
public class RemoteControl {
    Command[] onCommands;
    Command[] offCommands;
        
    public RemoteControl(){
        onCommands = new Command[2];
        offCommands = new Command[2];
        
        Command noCommand = new NoCommand();
        for(int i=0; i<2; i++){
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
    }
    
    //将命令对象加入到遥控器中,方法参数为遥控按钮的编号,开的命令,关的命令。
    public void setCommand(int slot,Command onCommand,Command offCommand){
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }
    //调用命令对象打开的操作
    public void onButtonWasPushed(int slot){
        onCommands[slot].execute();
    }
    //调用命令对象关闭的操作
    public void OffButtonWasPushed(int slot){
        offCommands[slot].execute();
    }
}

  最后我们来进行测试

public class Test {
    public static void main(String[] args) {
        //创建一个遥控器
        RemoteControl remoteControl = new RemoteControl();
        
        //创建电灯、音响装置对象
        Light light = new Light();
        Stereo stereo = new Stereo();
        
        //创建所有装置的命令对象
        LightOnCommand lightOnCommand = new LightOnCommand(light);
        LightOffCommand lightOffCommand = new LightOffCommand(light);
        StereoOnCommand stereoOnCommand = new StereoOnCommand(stereo);
        StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo);
        
        //将所有命令对象加载到遥控器中
        remoteControl.setCommand(0, lightOnCommand, lightOffCommand);
        remoteControl.setCommand(1, stereoOnCommand, stereoOffCommand);
        
        //下面进行开与关按钮测试
        remoteControl.onButtonWasPushed(0);
        remoteControl.OffButtonWasPushed(0);
        System.out.println("------");
        remoteControl.onButtonWasPushed(1);
        remoteControl.OffButtonWasPushed(1);
    }
}

  运行结果如下:

  

  当然这里还没有撤销操作,其实撤销就是倒过来,我们现在稍微加下某些代码就可以实现了。

  首先在Command接口中添加撤销操作方法undo

//创建一个命令对象的接口,所以命令都实现此接口
public interface Command {
    //只需一个方法
    public void execute();
    public void undo();
}

  接者在LightOnCommand中实现这个方法,因为开灯反过来就是添加light.off()方法

@Override
public void undo() {
      light.on();
 }

  同样道理,在其他命令对象中加入相应的undo。最后,我们在遥控器中加入一个撤销按钮

//撤销按钮遥控器对象
public class RemoteControlWithUndo {
    Command[] onCommands;
    Command[] offCommands;
    //撤销前一个命令对记录在这个对象中
    Command undoCommand;
        
    public RemoteControlWithUndo(){
        onCommands = new Command[2];
        offCommands = new Command[2];
        
        Command noCommand = new NoCommand();
        for(int i=0; i<2; i++){
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
        undoCommand = noCommand;
    }
    
    public void setCommand(int slot,Command onCommand,Command offCommand){
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }
    //调用命令对象打开的操作
    public void onButtonWasPushed(int slot){
        onCommands[slot].execute();
        //当按下按钮,我们取得这个命令,并先执行它,然后在记录中保存这个命令
        undoCommand = onCommands[slot];
    }
    //调用命令对象关闭的操作
    public void offButtonWasPushed(int slot){
        offCommands[slot].execute();
        undoCommand = offCommands[slot];
    }
    //调用撤销按钮
    public void undoButtonWasPushed(){
        undoCommand.undo();
    }
}

  最后测试下撤销操作。

public class Test {
    public static void main(String[] args) {
        //创建一个遥控器
        RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();
        
        //创建电灯、音响装置对象
        Light light = new Light();
        Stereo stereo = new Stereo();
        
        //创建所有装置的命令对象
        LightOnCommand lightOnCommand = new LightOnCommand(light);
        LightOffCommand lightOffCommand = new LightOffCommand(light);
        StereoOnCommand stereoOnCommand = new StereoOnCommand(stereo);
        StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo);
        
        //将所有命令对象加载到遥控器中
        remoteControl.setCommand(0, lightOnCommand, lightOffCommand);
        remoteControl.setCommand(1, stereoOnCommand, stereoOffCommand);
        
        //下面进行开与关按钮测试
        remoteControl.onButtonWasPushed(0);
        remoteControl.offButtonWasPushed(0);
        System.out.println("---撤销关闭电灯---");
        remoteControl.undoButtonWasPushed();
        System.out.println();
        
        remoteControl.onButtonWasPushed(1);
        System.out.println("---撤销打开音响---");
        remoteControl.onButtonWasPushed(1);
    }
}

  运行结果如下:

      

  好了,这就是一个简单的命令模式了,重点在于将“请求”封装成对象。然后将这对象进行传输。

  

  下一节:适配器模式

 

posted @ 2017-03-06 16:49  哀&RT  阅读(178)  评论(0编辑  收藏  举报