设计模式六之命令模式1

  命令模式,如果有一个遥控器,万能的,不是说一个空调万能遥控器可以遥控几乎所有品牌的遥控器,而是一个遥控器作为一个智能家居的入口,把所有智能家居的入口给绑定起来,控制所有的开关动作。将所有的命令组合起来,组成一道简单地命令,这样或许比较好。于是就出现了命令模式。

  命令模式其实是把命令和对象的执行方法绑在一起,传递一个对象,把对象的请求者和执行者分离开来,实现解耦。 

  下面贴一个简化的代码,

  总共六个类,simpleControl,Ligth,LightOn,LightOff,Command,Test.

  simpleControl,作为全局控制类,可以说是一个容器,在这里面去给每个插槽设置命令,可以动态设置,注意其针对的是命令而不是命令的主体。然后可以调用命令中得执行操作,因为这是接口对应的。

  Light,是作为对象,其本身可以有很多方法,但是因为命令模式所谓把命令给拆出去了,于是只保留了一些公共的属性在里面,比如我这里的name.

  LightOn和LightOff,作为实际的实现了命令接口的exec方法的类,首先是构造器,必须要说明是对哪个对象进行抽象而得出的命令,谁是主体。然后是这里分出来的命令,我这里面就是off和on,注意我这里分出了两个类来些。明明if-else就可以解决,为说明还开一个类,这就是解耦。

  Command接口,只是提供一个统一的全局需要执行的方法,这个就略要求所有的主体可以抽象有一个执行的方法。

package com.csshu.command1;

public interface Command {
    public void exec();
}
package com.csshu.command1;

public class Light {private String name;
    
    public Light(String name){
        this.name = name;
    }public String getName(){
        return name;
    }
}
package com.csshu.command1;

public class LightOff implements Command{
    private Light light;
    
    public LightOff(Light light) {
        this.light = light;
    }
    
    @Override
    public void exec() {
        System.out.println("The" + light.getName() + "light is off");
    }
    

}
package com.csshu.command1;

public class LightOn implements Command{
    private Light light;
    
    public LightOn(Light light){
        this.light = light;
    }
    
    @Override
    public void exec() {
        System.out.println("The " +light.getName() +" light is on");
    }
    

}
package com.csshu.command1;

public class SimpleControl {
    Command command;
    
    public void setSlot(Command command){
        this.command = command; 
    }
    
    public void buttonWasPressed(){
        command.exec();
    }
    
}
package com.csshu.command1;

public class Test {
    public static void main(String[] args) {
        SimpleControl sm = new SimpleControl();
        
        Light light = new Light("sss");
        
        LightOff off = new LightOff(light);
        LightOn on = new LightOn(light);
        
        sm.setSlot(off);
        sm.buttonWasPressed();
        
        sm.setSlot(on);
        sm.buttonWasPressed();
    }
    
}

 

  

  定义:将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销操作。
 
  一个命令对象通过在特定接受者上绑定一组动作(打开车库门、开灯)来封装一个请求(execute)。要达到这一点,命令对象将动作和接受者包进对象中(对象,door,声明一个引用,通过setCommand来设置进去,而动作就是execute,可以在这里面执行door.up,door.lightOn)。这个对象只暴露出一个execute方法,当此方法被调用的时候,接受者就会进行这些动作。从外面看,其他对象不知道究竟哪个接受者进行了哪些动作。只知道如果调用execute方法,请求的目的就会达到。
 
  我们也看到了利用命令来参数化对象的一些例子。再回到餐厅,一整天下来,女招待参数化许多订单。在简单遥控器中,我们先用一个”打开电灯”命令加载按钮插槽,稍后又将命令替换成为另一个”打开车库门”命令。就喝女招待一样,遥控器插槽根本不在乎所拥有的是什么命令对象,只要该命令对象实现了command接口就可以了。
 
  RemoteLoader创建许多命令对象,然后将其加载到遥控器的插槽中。每个命令对象都封装了某个家电自动化装置的一项请求。
RemoteControl管理一组命令对象,每个按钮都有一个命令对象。每当按下按钮,就调用相应地xxButtonWasPushed()方法,间接造成该命令的execute()方法被调用。
  所有的遥控器命令都实现这个Command接口,此接口中包含了一个方法,也就是execute(),命令封装了某个特定厂商类的一组动作,遥控器可以通过调用execute方法,执行这些动作。这些厂商类被用来控制特定的家电自动化装置。在这里,我们用Light类当做例子。
利用Command接口,每个动作都被实现成一个简单地命令对象。命令对象持有对一个厂商类的实例的引用,并实现了一个execute方法。这个方法会调用厂商类实例的一个或多个方法,完成特定的行为。在这个例子中,有两个类,分别打开电灯与关闭电灯。
 
  命令模式的更多用途:队列请求
 
  命令可以将运算块打包(一个接受者和一组动作),然后将它传来传去,就像是一般的对象一样。现在,即使在命令对象被创建许久之后,运算仍然可以被调用。事实上,它甚至可以在不同的线程中被调用。我们可以利用这样的特性衍生一些应用,例如:日程安排(Scheduler)、线程池、工作队列等。
 
  想象有一个工作队列:你在某一段添加命令,然后另一端则是线程。线程进行下列的动作:从队列中取出一个命令,调用它的execute()方法,等待这个调用完成,然后将此命令对象丢弃,再取出下一个命令——
 
  线程从队列中一个个地删除命令对象,然后调用命令对象的execute方法。一旦完成了,就会再去处理下一个新的命令对象。
 
  这样能有效地把运算限制在固定数目的线程中进行。
 
  请注意,工作队列类和进行计算的对象之间完全是解耦的。此刻线程可能在进行财务运算,下一刻却在读取网络数据。工作队列对象不在乎到底做些数目,它们只知道取出命令对象,然后调用其execute方法。类似地,它们只要是实现命令模式的对象,就可以放入队列里,当线程可用时,就调用此对象的execute方法。
 
  日志请求,新增两个方法store\load,就能支持这一点对更高级的应用而言,这些技巧可以被扩展应用到事物(transaction)处理中,也就是说,一整群操作必须全部进行完成,或者没有进行任何的操作。
posted @ 2015-11-27 23:51  likeshu  阅读(149)  评论(0编辑  收藏  举报