设计模式之命令模式(一)

在本次学习过程当中,咱们把封装带到一个全新的境界:把方法调用(method invocation)封装起来。没错,经过封装方法调用,咱们能够把运算块包装成形。java

因此调用此运算的对象不须要关心事情是如何进行的,只要知道如何使用包装成形的方法来完成它就能够。经过封装方法调用,也能够作一些很聪明的事情,例如记录日志,或者重复使用这些封装来实现撤销。让咱们开始吧学习

如今有一个用户A,他们家有不少家电,在装修的时候,他让装修公司把这些家电当成了一个总体,想要经过一个遥控器就能控制家里的电灯、风扇、热水器、音响设备和其余的相似的可控制装置,这样的话就显得很高大上。测试

因此呢,他让每一个厂商投提供了一组Java类,用来控制家电。手上又有一个遥控器,但愿咱们可以建立一组控制遥控器的API,让每一个插槽都能控制一个或一组装置,即经过一个遥控器就能控制全部家电,是否是很酷。this

咱们先来看下厂商给的类。设计

这个类确实很多呀,并且接口也各有差别。还有更麻烦的,随着家电数量的增长,这样的类还会愈来愈多。那么,如何设计一个遥控器API就变得颇有挑战性了是吧。日志

因此,命令模式应运而生了。在咱们的设计中,采用“命令模式”,利用命令对象,把请求(例如打开电灯)封装成一个特定对象(例如客厅电灯对象)。因此,若是对每一个按钮都存储一个命令对象,那么当按钮被按下的时候,就能够请命令对象作相关的工做。遥控器并不须要知道工做内容是什么,只要有个命令对象能和正确的对象沟通,把事情作好就能够了。这样,遥控器和电灯对象都解耦了。code

可能把遥控器换成餐厅点餐,你们会更容易理解。我在这里简单描述下:首先顾客到了餐厅,根据菜单点了一部分菜,把菜单给服务员;服务员拿到了订单,就提交到柜台上,并向后厨喊了一声“xx号桌xx订单”来了;后厨根据菜单进行配菜,烧菜。全称服务员都不须要知道订单具体内容是什么,只要将桌上的客户点的餐提供给后厨便可,这和咱们的遥控器就是一个道理了。对象

第一个命令对象

实现命令接口

那咱们就来建立咱们的命令对象吧。首先,咱们得让全部的命令对象实现相同的包含一个方法的接口。在餐厅订餐的例子上,就是建立订单,咱们在程序的世界里,取名叫作execute()blog

public interface Command {
    public void execute();
}
实现一个打开电灯的命令

如今,假设想实现一个打开电灯的命令。根据以前看到的厂商提供的类,Light类有两个方法,on和off。接口

// 这是一个命令,因此须要实现Command接口
public class LightOnCommand implements Command {
    Light light;

// 构造器传入某个电灯,以便让这个命令控制,而后记录在实例变量中
    public LightOnCommand(Light light) {
        this.light = light;
    }

// 这个execute方法调用接收对象的on方法
    public void execute() {
        light.on();
    }

}

使用命令对象

如今,咱们让遥控器工做起来,先来点简单的。假设遥控器只有一个按钮和对应的插槽,能够控制一个装置:

public class SimpleRemoteControl {
// 有一个插槽持有命令,而这个命令控制着一个装置
    Command slot;
 
    public SimpleRemoteControl() {}
 
// 这个方法用来设置插槽控制的命令
    public void setCommand(Command command) {
        slot = command;
    }
 
// 当按下按钮时,这个方法就会被调用,使得当前命令衔接插槽,并调用它的execute方法
    public void buttonWasPressed() {
        slot.execute();
    }
}

就这样咱们就能实现一个简单的遥控器了。请看咱们的测试

public class RemoteControlTest {
    public static void main(String[] args) {
    // 遥控器就是调用者,会传入一个命令对象,能够用来发出请求
        SimpleRemoteControl remote = new SimpleRemoteControl();
    // 如今建立一个电灯对象,此对象也就是请求的接收者
        Light light = new Light();
    // 这里建立一个命令,而后将接收者传给它
        LightOnCommand lightOn = new LightOnCommand(light);
    
    // 把命令传给调用者
        remote.setCommand(lightOn);
    // 模拟按下按钮
        remote.buttonWasPressed();
    }
    
}

定义命令模式

通过订餐流程的理解,以及刚才这个小练习,相信你也对命令模式内的类 和对象如何互动理解得很清楚了吧。那咱们在这里趁热打铁,定义一下命令模式。

命令模式将请求封装成对象,以便使用不一样的请求,队列或者日志来参数化其余对象。命令模式也支持可撤销的操做。

仔细想一想,咱们知道有一个命令对象经过在特定接收者上绑定一组动做来封装一个请求。要达到这一点,命令对象将动做和接收者包进对象中。这个对象只暴露出一个execute()方法,当此方法被调用的时候,接收者就会进行这些动做。从外面来看,其余对象不知道究竟哪一个接收者进行了哪些动做,只知道若是调用execute()方法,请求的目的就能达到。

让咱们来看下命令模式的类图:

好了,经过这个简单的小练习,咱们知道如何控制电灯的开关了。在前面厂商给的类中,还有好多方法,好比电风扇、吊灯、电视机、音响等等。控制单个咱们已经能搞定了,那控制多个呢?是否是同理呢?仍是你有更好的方式呢?小编想请你先动动你的小手,咱们下次见分晓。

爱生活,爱学习,爱感悟,爱挨踢

相关文章
相关标签/搜索