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


    8.1开关与电灯

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

    8.2 模式定义

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

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

      1)抽象化

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

      2)实现化

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

      3)脱耦

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

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

    8.3 一般化分析

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

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

      1)开关

      2)电灯

      3)电线

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

      

    8.4 一般化实现

    8.4.1 建立抽象开关

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

    package com.demo.common;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 开关基类
     */
    public abstract class AbstractSwitch {
    
        //打开开关
        public abstract void turnOn();
    
        //照明
        public abstract void light();
    
        //关闭开关
        public abstract void turnOff();
    
        //开灯照明
        public final void makeLight(){
            this.turnOn();
            this.light();
            this.turnOff();
        }
    
    }

    8.4.2 电灯实现

    1. 白炽灯实现——IncandescentLight

    package com.demo.common.sub;
    
    import com.demo.common.AbstractSwitch;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 白炽灯
     */
    public class IncandescentLight extends AbstractSwitch {
    
        //打开开关方法实现
        @Override
        public void turnOn() {
            System.out.println("白炽灯打开了……");
        }
    
        //照明方法实现
        @Override
        public void light() {
            System.out.println("白炽灯照明!");
        }
    
        //关闭开关方法实现
        @Override
        public void turnOff() {
            System.out.println("白炽灯关闭了……");
        }
    }

    2. 水晶灯实现——CrystalLight

    package com.demo.common.sub;
    
    import com.demo.common.AbstractSwitch;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 水晶灯
     */
    public class CrystalLight extends AbstractSwitch {
    
        //打开开关方法实现
        @Override
        public void turnOn() {
            System.out.println("水晶灯打开了……");
        }
    
        //照明方法实现
        @Override
        public void light() {
            System.out.println("水晶灯照明!");
        }
    
        //关闭开关方法实现
        @Override
        public void turnOff() {
            System.out.println("水晶灯关闭了……");
        }
    
        /**
         * 使用遥控开关控制开灯
         * @param operColor 灯颜色
         */
        public final void makeRemoteLight(int operColor){
            //打开开关,接通电流
            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 客户端测试

    import com.demo.common.AbstractSwitch;
    import com.demo.common.sub.CrystalLight;
    import com.demo.common.sub.IncandescentLight;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 客户端应用程序
     */
    public class Client {
    
        public static void main(String[] args) {
            //白炽灯实例
            AbstractSwitch light = new IncandescentLight();
    
            //水晶灯实例
            CrystalLight light2 = new CrystalLight();
    
            //一般开关
            System.out.println("---一般开关---");
            light.makeLight();
    
            //遥控开关
            System.out.println("
    ---遥控开关---");
            light2.makeRemoteLight(1);
        }
    
    }

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

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

    8.4.4 对于扩展功能的思考

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

    8.5 桥接模式分析方法

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

      

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

    8.6.1 创建电灯接口

    package com.demo.bridge.lights;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 电灯接口
     */
    public interface ILight {
    
        //接通电流
        public void electricConnected();
    
        //照明
        public void light();
    
        //断开电流
        public void electricClosed();
    
    }

    8.6.2 创建开关

    1. 创建一般开关——BaseSwitch

    package com.demo.bridge.switchs;
    
    import com.demo.bridge.lights.ILight;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 开关顶层类
     */
    public class BaseSwitch {
    
        //使用组合,设置ILight为内部私有属性,此为桥梁
        protected ILight light;
    
        //构造方法将外部的light类型注入进来
        public BaseSwitch(ILight light){
            this.light = light;
        }
    
        /**
         * 开灯方法
         */
        public final void makeLight(){
            //打开开关,接通电流
            this.light.electricConnected();
            //照明
            this.light.light();
            //关闭开关,断开电流
            this.light.electricClosed();
        }
    
    }

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

    2. 创建遥控开关——RemoteControlSwitch

    package com.demo.bridge.switchs;
    
    import com.demo.bridge.lights.ILight;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 遥控开关,继承BaseSwitch扩展功能
     */
    public class RemoteControlSwitch extends BaseSwitch{
    
        //构造方法
        public RemoteControlSwitch(ILight light) {
            super(light);
        }
    
        /**
         * 使用遥控开关控制开灯
         * @param operColor 灯颜色
         */
        public final void makeRemoteLight(int operColor){
            //打开开关,接通电流
            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

    package com.demo.bridge.lights.impl;
    
    import com.demo.bridge.lights.ILight;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 白炽灯实现
     */
    public class IncandescentLight implements ILight{
    
        //接通电流
        public void electricConnected() {
            System.out.println("白炽灯被打开了……");
        }
    
        //照明
        public void light() {
            System.out.println("白炽灯照明!");
        }
    
        //断开电流
        public void electricClosed() {
            System.out.println("白炽灯被关闭了……");
        }
    }

    2. 水晶灯实现——CrystalLight

    package com.demo.bridge.lights.impl;
    
    import com.demo.bridge.lights.ILight;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 水晶灯实现
     */
    public class CrystalLight implements ILight {
    
        //接通电流
        public void electricConnected() {
            System.out.println("水晶灯被打开了……");
        }
    
        //照明
        public void light() {
            System.out.println("水晶灯照明!");
        }
    
        //断开电流
        public void electricClosed() {
            System.out.println("水晶灯被关闭了……");
        }
    }

    8.6.4 客户端测试

    1. 一般化测试

    import com.demo.bridge.lights.ILight;
    import com.demo.bridge.lights.impl.CrystalLight;
    import com.demo.bridge.lights.impl.IncandescentLight;
    import com.demo.bridge.switchs.BaseSwitch;
    import com.demo.bridge.switchs.RemoteControlSwitch;
    
    /**
     * Created by Daniel on 2018/3/18.
     * 客户端应用程序
     */
    public class ClientForBridge {
    
        public static void main(String[] args) {
            //白炽灯实例
            ILight incandescentLight = new IncandescentLight();
            //水晶灯实例
            ILight crystalLight = new CrystalLight();
    
            //一般开关
            System.out.println("---一般开关---");
            BaseSwitch switch1 = new BaseSwitch(incandescentLight);
            switch1.makeLight();
            System.out.println("
    ---遥控开关---");
            RemoteControlSwitch remoteControlSwitch = new RemoteControlSwitch(crystalLight);
            remoteControlSwitch.makeRemoteLight(1);
    
        }
    
    }

    运行结果:

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

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

      将遥控开关部分:

    RemoteControlSwitch remoteControlSwitch = new RemoteControlSwitch(crystalLight);

      修改为:

    RemoteControlSwitch remoteControlSwitch = new RemoteControlSwitch(incandescentLight);

    运行结果:

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

    8.7 使用场合

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

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

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

  • 相关阅读:
    如何辨别护照的种类
    C#枚举中使用Flags特性
    那些年,我们一起学WCF--(7)PerSession实例行为
    64位系统使用Access 数据库文件的彻底解决方法
    从Excel中导入数据时,提示“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序”的解决办法
    TortoiseSVN与VisualSVN Server搭建SVN版本控制系统
    解决Winform程序在不同分辨率系统下界面混乱
    【已解决】Https请求——基础连接已经关闭 发送时发生错误
    Entity Framework Code First学习系列目录
    PowerDesigner之PDM(物理概念模型)各种属性建立如PK,AK等
  • 原文地址:https://www.cnblogs.com/danielleee/p/8595547.html
Copyright © 2020-2023  润新知