08-开关与电灯:桥接模式

摘要:
桥接模式使得软件系统能够轻松地沿着多个方向进行变化,而又不引入额外的复杂度。这就是桥接模式的用意所在。我们知道,开关控制电灯,开关接通电源,电灯亮;开关断开,电灯熄灭。开关和电灯之间的关系如图所示:8.4一般化实现8.4.1建立抽象开关新建抽象开关基类“AbstractSwitch”。

8.1开关与电灯

本章背景故事是生活中常用的开关与电灯。

8.2 模式定义

桥接模式(Bridge Pattern),也称为桥梁模式。在软件系统中,某些类型由于自身的逻辑,具有两个或多个维度的变化,如何应对这种“多维度的变化”?桥接模式使得软件系统能够轻松地沿着多个方向进行变化,而又不引入额外的复杂度。

桥接模式的用意是“将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化”。这句话有三个关键词,即抽象化、实现化和脱耦。

1)抽象化

存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同的实体当作同样的实体对待。

2)实现化

抽象化给出的具体实现,就是实现化。

3)脱耦

所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称为脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开来,或者说是将它们之间的强关联改为弱关联。

将两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改为弱关联。因此,桥接模式中的脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以相对独立地变化。这就是桥接模式的用意所在。

8.3 一般化分析

本章我们来介绍开关和电灯的例子,看看开关和电灯之间到底如何运作才是最理想的。

在示例中出现了以下几个角色:

1)开关

2)电灯

3)电线

我们先来分析一般情况下,该如何实现。我们知道,开关控制电灯,开关接通电源,电灯亮;开关断开,电灯熄灭。这样看来,开关应该是一个基类,类中含有开灯、关灯、照明等抽象方法,还要有一个开灯照明的方法提供给外部应用调用;然后,电灯继承开关基类,具体实现开灯、关灯、照明等抽象方法,告诉外部应用现在使用的是哪盏灯。开关和电灯之间的关系如图所示:

08-开关与电灯:桥接模式第1张

8.4 一般化实现

8.4.1 建立抽象开关

新建抽象开关基类“AbstractSwitch”。该类中存在三个抽象方法:打开开关、照明和关闭开关,还有一个提供给外部应用调用的开灯照明方法。

packagecom.demo.common;

/*** Created by Daniel on 2018/3/18.
 * 开关基类
 */
public abstract classAbstractSwitch {

    //打开开关
    public abstract voidturnOn();

    //照明
    public abstract voidlight();

    //关闭开关
    public abstract voidturnOff();

    //开灯照明
    public final voidmakeLight(){
        this.turnOn();
        this.light();
        this.turnOff();
    }

}

8.4.2 电灯实现

1. 白炽灯实现——IncandescentLight

packagecom.demo.common.sub;

importcom.demo.common.AbstractSwitch;

/*** Created by Daniel on 2018/3/18.
 * 白炽灯
 */
public class IncandescentLight extendsAbstractSwitch {

    //打开开关方法实现
@Override
    public voidturnOn() {
        System.out.println("白炽灯打开了……");
    }

    //照明方法实现
@Override
    public voidlight() {
        System.out.println("白炽灯照明!");
    }

    //关闭开关方法实现
@Override
    public voidturnOff() {
        System.out.println("白炽灯关闭了……");
    }
}

2. 水晶灯实现——CrystalLight

packagecom.demo.common.sub;

importcom.demo.common.AbstractSwitch;

/*** Created by Daniel on 2018/3/18.
 * 水晶灯
 */
public class CrystalLight extendsAbstractSwitch {

    //打开开关方法实现
@Override
    public voidturnOn() {
        System.out.println("水晶灯打开了……");
    }

    //照明方法实现
@Override
    public voidlight() {
        System.out.println("水晶灯照明!");
    }

    //关闭开关方法实现
@Override
    public voidturnOff() {
        System.out.println("水晶灯关闭了……");
    }

    /*** 使用遥控开关控制开灯
     * @paramoperColor 灯颜色
     */
    public final void makeRemoteLight(intoperColor){
        //打开开关,接通电流
        this.turnOn();
        //照明
        this.light();
        String color = "";
        switch(operColor){
            case 1:
                color = "暖色";
                break;
            case 2:
                color = "蓝色";
                break;
            case 3:
                color = "红色";
                break;
            default:
                color = "白色";
                break;
        }
        System.out.println("---现在是"+color+"!");

        //关闭开关,断开电流
        this.turnOff();
    }
}

8.4.3 客户端测试

importcom.demo.common.AbstractSwitch;
importcom.demo.common.sub.CrystalLight;
importcom.demo.common.sub.IncandescentLight;

/*** Created by Daniel on 2018/3/18.
 * 客户端应用程序
 */
public classClient {

    public static voidmain(String[] args) {
        //白炽灯实例
        AbstractSwitch light = newIncandescentLight();

        //水晶灯实例
        CrystalLight light2 = newCrystalLight();

        //一般开关
        System.out.println("---一般开关---");
        light.makeLight();

        //遥控开关
        System.out.println("
---遥控开关---");
        light2.makeRemoteLight(1);
    }

}

注意:要想使用水晶灯的遥控功能就必须创建水晶灯实例对象,不能使用超类类型,因为超类中没有遥控的功能。

运行客户端程序,结果如下图所示:

08-开关与电灯:桥接模式第2张

8.4.4 对于扩展功能的思考

已经实现了开灯、照明和关灯,是不是已经解决了所有的问题呢?答案是否定的。试想一下,我现在想用遥控开关遥控白炽灯,该怎么办呢?再创建一个子类?这样开销太大了。白炽灯已经存在,遥控开关也已经存在,为什么还要新建一个类呢?问题是,我们一开始的设计思路就是错误的。不应该使用继承,因为继承使开关和电灯关联得太强了,也就是一个开关控制一种灯,要想更换其他种类的电灯就必须配备相应的开关才行。更换电灯的同时还要更换开关,这是不应该出现的。

8.5 桥接模式分析方法

我们重新分析一下,其实,开关和电灯是完全分开的两个部分,是彼此独立的工作,不应该因为对方的变换而受到影响。所以,要使用组合,不能使用继承。重新建立关系图如下:

08-开关与电灯:桥接模式第3张

8.6 开关与电灯的桥接模式实现

8.6.1 创建电灯接口

packagecom.demo.bridge.lights;

/*** Created by Daniel on 2018/3/18.
 * 电灯接口
 */
public interfaceILight {

    //接通电流
    public voidelectricConnected();

    //照明
    public voidlight();

    //断开电流
    public voidelectricClosed();

}

8.6.2 创建开关

1. 创建一般开关——BaseSwitch

packagecom.demo.bridge.switchs;

importcom.demo.bridge.lights.ILight;

/*** Created by Daniel on 2018/3/18.
 * 开关顶层类
 */
public classBaseSwitch {

    //使用组合,设置ILight为内部私有属性,此为桥梁
    protectedILight light;

    //构造方法将外部的light类型注入进来
    publicBaseSwitch(ILight light){
        this.light =light;
    }

    /*** 开灯方法
     */
    public final voidmakeLight(){
        //打开开关,接通电流
        this.light.electricConnected();
        //照明
        this.light.light();
        //关闭开关,断开电流
        this.light.electricClosed();
    }

}

注意:将ILight电灯接口作为开关基类的属性使用,这就是聚合的方式。而开关基类的开灯照明方法,是委托给ILight电灯接口完成的。这是一般开关实现,下面看看遥控开关。

2. 创建遥控开关——RemoteControlSwitch

packagecom.demo.bridge.switchs;

importcom.demo.bridge.lights.ILight;

/*** Created by Daniel on 2018/3/18.
 * 遥控开关,继承BaseSwitch扩展功能
 */
public class RemoteControlSwitch extendsBaseSwitch{

    //构造方法
    publicRemoteControlSwitch(ILight light) {
        super(light);
    }

    /*** 使用遥控开关控制开灯
     * @paramoperColor 灯颜色
     */
    public final void makeRemoteLight(intoperColor){
        //打开开关,接通电流
        this.light.electricConnected();
        //照明
        this.light.light();
        String color = "";
        switch(operColor){
            case 1:
                color = "暖色";
                break;
            case 2:
                color = "蓝色";
                break;
            case 3:
                color = "红色";
                break;
            default:
                color = "白色";
                break;
        }
        System.out.println("--现在是"+color+"!");

        //关闭开关,断开电流
        this.light.electricClosed();
    }
}

注意:遥控开关的方法中,只做了关于电灯颜色的控制,电灯开关控制仍是委托给ILight电灯接口的。

8.6.3 电灯实现

1. 白炽灯实现——IncandescentLight

packagecom.demo.bridge.lights.impl;

importcom.demo.bridge.lights.ILight;

/*** Created by Daniel on 2018/3/18.
 * 白炽灯实现
 */
public class IncandescentLight implementsILight{

    //接通电流
    public voidelectricConnected() {
        System.out.println("白炽灯被打开了……");
    }

    //照明
    public voidlight() {
        System.out.println("白炽灯照明!");
    }

    //断开电流
    public voidelectricClosed() {
        System.out.println("白炽灯被关闭了……");
    }
}

2. 水晶灯实现——CrystalLight

packagecom.demo.bridge.lights.impl;

importcom.demo.bridge.lights.ILight;

/*** Created by Daniel on 2018/3/18.
 * 水晶灯实现
 */
public class CrystalLight implementsILight {

    //接通电流
    public voidelectricConnected() {
        System.out.println("水晶灯被打开了……");
    }

    //照明
    public voidlight() {
        System.out.println("水晶灯照明!");
    }

    //断开电流
    public voidelectricClosed() {
        System.out.println("水晶灯被关闭了……");
    }
}

8.6.4 客户端测试

1. 一般化测试

importcom.demo.bridge.lights.ILight;
importcom.demo.bridge.lights.impl.CrystalLight;
importcom.demo.bridge.lights.impl.IncandescentLight;
importcom.demo.bridge.switchs.BaseSwitch;
importcom.demo.bridge.switchs.RemoteControlSwitch;

/*** Created by Daniel on 2018/3/18.
 * 客户端应用程序
 */
public classClientForBridge {

    public static voidmain(String[] args) {
        //白炽灯实例
        ILight incandescentLight = newIncandescentLight();
        //水晶灯实例
        ILight crystalLight = newCrystalLight();

        //一般开关
        System.out.println("---一般开关---");
        BaseSwitch switch1 = newBaseSwitch(incandescentLight);
        switch1.makeLight();
        System.out.println("
---遥控开关---");
        RemoteControlSwitch remoteControlSwitch = newRemoteControlSwitch(crystalLight);
        remoteControlSwitch.makeRemoteLight(1);

    }

}

运行结果:

08-开关与电灯:桥接模式第4张

2. 让遥控开关遥控白炽灯

如果我们想要用遥控开关控制白炽灯,我们只需要将白炽灯传入遥控开关的构造方法中即可实现。

将遥控开关部分:

RemoteControlSwitch remoteControlSwitch = new RemoteControlSwitch(crystalLight);

修改为:

RemoteControlSwitch remoteControlSwitch = new RemoteControlSwitch(incandescentLight);

运行结果:

08-开关与电灯:桥接模式第5张

正如运行结果,遥控开关可以控制白炽灯了!

8.7 使用场合

1)不希望在抽象类和它的实现部分之间有一个固定的绑定关系;

2)类的抽象及实现都应该可以通过生成子类的方法加以扩充;

3)对一个抽象的实现部分的修改对客户不产生影响,即客户的代码不必重新编码。

免责声明:文章转载自《08-开关与电灯:桥接模式》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ant-design-vue 之form表单中label-col和wrapper-col使用ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致”下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

VMware 下虚拟机桥接模式在局域网中访问互通,并实现VM IP固定

一 场景 我本地VM上搭建的gitlab 二 准备工作 #查看 本地 IP 信息、掩码、网关 cmd 模式 : ipconfig /all 以太网适配器 以太网: 连接特定的 DNS 后缀 . . . . . . . : 描述. . . . . . . . . . . . . . . : Intel(R) Ethernet Conn...

VirtualBox 桥接模式,虚拟机ping不通宿主机

VirtualBox 桥接模式,主机能够ping通虚拟机,但虚拟机不能ping通主机 解决方案: 打开控制面板,找到Windows Defender 防火墙,点击高级设置,在入站规则里找到文件和打印机共享(回显请求 - ICMPv4-In),右键启用规则 如果是在同一网段下,启用本地子网就可以了 参考:https://www.cnblogs.com/zi...

联通 F677V2 光猫改桥接

联通 F677V2 光猫改桥接 一、前言 如今的宽带服务提供商而为了简化用户的操作,将光猫集成了很多功能,除了最基本的光电转换功能外,还集成了路由功能、DHCP服务、NAT、IPTV、WIFI功能等。而光猫的硬件只能满足家庭网络的基本需求,如果将光猫作为家庭网络的中心节点,由于光猫的性能问题,可能无法满足需求,长时间运行造成网络不稳定的状况。并且光猫路由还...

虚拟机无法上网的问题:无法启动VMnet0等问题

  虚拟机无法上网,由于之前安装过虚拟机,后来将它卸载了,然后重新安装,最后出现了虚拟机无法上网。刚开始以为是系统的原因,于是就通过linux命令查看系统里面的网卡时是否启动,如:/etc/init.d/network status 查看网刊启动状况,重启网卡:service network restart 。设置修改/etc/sysconfig/netw...

VM安装后没有桥链接协议解决方法

      从昨天到今天各种折腾的。网络就是各种不通,能使用的手段都上了,还是不行。奇怪的连DNS都ping不通。      ping DNS时一致报:  Destination Host Unreachable 。。。           VM无法将网络更改为桥接状态:没有未桥接的主机网络适配器     https://www.cnblogs.com/g...

【Unity3D与23种设计模式】桥接模式(Bridge)

GoF定义: “将抽象与实现分离,使二者可以独立的变化” 游戏中,经常有这么一种情况 基类角色类(ICharacter),下面有子类士兵类(ISoldier)、敌军类(IEnemy) 基类武器类(IWeapon),下面有子类枪类(IGun)、炮类(ICannon) 当然,有用枪的士兵,有用炮的士兵 这么一组合,就是2*2 = 4个类 游戏后期,当角...