[学习笔记]设计模式[5]-{命令模式}

来源:互联网 发布:mac 界面英文变中文版 编辑:程序博客网 时间:2024/05/16 12:22

设计模式

当我们在开发系统时,可能会遇到这样的问题:我需要对一些互无关联的类进行相似的操作,而且这些操作还有可能在未来有变化,需要这个操作的类可能会增加。
想想我们的第一个设计原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
在这种场景下,类可能是不需要变化的,但是可能会发生变化的是对类的”操作”。那么我们要怎么把”操作”独立出来呢,这里的命令模式就可以很好的解决这个问题。

命令模式

先从正式的定义开始:
命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
定义中的“请求”就可以看做是对对象进行的操作的请求或者对类进行更改的请求。
我们拿书上的例子来理解命令模式:你需要实现一个遥控器的类,这个类需要对一些家电,例如电视类、壁灯类、风扇类等等进行操作。下面是其中的一些类:

public class TV(){    public void on(){...}    public void off(){...}    public void setChannel(int i){...}    public void setVolume(int i){...}}
public class CeilingLight(){    public void on(){...}    public void off(){...}    public void dim(){...}}
public class CeilingFan(){    public void on(){...}    public void off(){...}    public void high(){...}    public void medium(){...}    public void low(){...}}

为了简洁,就省略了类中的方法实现。。。
很明显,如果我们需要操作这些类,就需要把这些类拿到遥控器类中。我们先看下面的这种实现方法:

public class Control{    private TV tv;    private CeilingLight ceilingLight;    private CeilingFan ceilingFan;    public Control(TV tv, CeilingLight ceilingLight, CeilingFan ceilingFan) {        this.tv = tv;        this.ceilingFan = ceilingFan;        this.ceilingLight = ceilingLight;    }    public void sendCommand(int i){        if(i == EnumUtil.TV_ON){            tv.on();        }else if(i == EnumUtil.TV_OFF){            tv.off();        }else if(i == EnumUtil.FAN_ON){            ceilingFan.on();        }else if(...){            ...        }        ....//太多了省略    }    ......}

很明显,上面的方法导致这样的问题:
1.如果增加或减少家电就需要动原来的代码。
2.如果我想调整按键的位置,就需要对原来的代码进行大规模的调整。
3.很容易写错。。。
从上面的描述可以知道,经常会变化的部分是调用厂商类的那部分。下面的命令模式就可以把“调用”的命令和遥控器解耦,使得遥控器不需要知道具体的命令。
首先定义一个命令的接口,这个接口需要继承他的类都需要实现执行命令的方法:

public interface Command{    public void excute();}

下面实现开电视机和关电视机两个动作:

public class TvOnCommand implements Command{    Tv tv;    public TvOnCommand(Tv tv){        this.tv = tv;    }    public void excute(){        tv.on();    }}
public class TvOffCommand implements Command{    Tv tv;    public TvOnCommand(Tv tv){        this.tv = tv;    }    public void excute(){        tv.off();    }}

这样,我们实现了第一步:将请求封装到类中。
下面是遥控器的实现类:

public class Control{    Command[] commands;    public Control(int n){  //遥控器有几个按钮        if(n > 0){            commands = new Command[n];        }    }    public void setCommand(int slot, Command command){        commands[slot] = command;    }    public void pushCommand(int slot){        commands[slot].excute();    }}

这样就实现了遥控器和命令的解耦,遥控器不需要知道每个按键是什么,是怎样工作的。
下面是具体的使用方法:

public class RemoteLoader{    public static void main(String[] args) {        Control control = new Control(4);        TV tv = new TV();        Light light = new Light();        TvOnCommand tvOnCommand = new TvOnCommand(tv);        TvOffCommand tvOffCommand = new TvOffCommand(tv);        LightOnCommand lightOnCommand = new LightOnCommand(light);        LightOffCommand lightOffCommand = new LightOffCommand(light);        control.setCommand(0,tvOnCommand);        control.setCommand(1,tvOffCommand);        control.setCommand(2,lightOnCommand);        control.setCommand(3,lightOffCommand);        //下面就可以使用遥控器了:        pushCommand(0);//打开电视机        pushCommand(1);//打开灯光    }}

上面的方式就是简单的命令模式了。最后是命令模式的类图:

0 0
原创粉丝点击