桥接模式

作者: Jackson杰 | 来源:发表于2019-03-07 11:36 被阅读32次

    一 定义

    桥接模式也成为桥梁模式,是结构型设计模式之一。现实生活中,桥梁具有连接两岸的作用,具有承接两边的作用。在程序中,两边具体指哪两边呢,接下来看定义。
    定义:将抽象部分与实现部分分离,使它们可以独立地进行变化。
    从桥接模式的定义,我们可以看出,桥接模式连接的两边,分别是抽象部分和实现部分,使它们独立变化,起到解耦的作用。

    二 模式结构


    角色介绍

    • Abstraction:抽象部分
      该类保持一个对实现部分对象的引用,该类中的方法需要调用实现部分的对象来实现。

    • RefinedAbstraction:优化的抽象部分
      抽象部分的具体实现,该类一般对抽象部分的方法进行完善和拓展。

    • Implementor:实现部分
      可以使接口或者抽象类,定义角色必须的行为和属性。

    • ConcreteImplementorA/ConcreteImplementorB :实现部分的具体实现
      完善实现部分中方法定义的具体逻辑。

    • Client:客户端

    • 实现部分的接口

    /*
     * 实现部分的抽象接口
     * @author Jackson
     * @version 1.0.0
     * since 2019 03 05
     */
    public interface Implementor {
    
        /**
         * 实现抽象部分的具体方法
         */
        public void operationImpl();
    }
    
    • 实现部分的具体实现一
    /*
     * 实现部分的具体实现一
     * @author Jackson
     * @version 1.0.0
     * since 2019 03 05
     */
    public class ConcreteImplementorA implements Implementor{
        @Override
        public void operationImpl() {
            // 具体的实现
        }
    }
    
    • 实现部分的具体实现二
    /*
     *  实现部分的具体实现二
     * @author Jackson
     * @version 1.0.0
     * since 2019 03 05
     */
    public class ConcreteImplementorB implements Implementor{
        @Override
        public void operationImpl() {
            // 具体的实现
        }
    }
    
    • 抽象部分的实现
    public abstract class Abstraction {
    
        private Implementor mImplementor;  // 声明一个成员变量引用实现部分的对象
    
        /**
         * 构造方法
         * @param implementor
         */
        public Abstraction(Implementor implementor){
            this.mImplementor=implementor;
        }
    
        /**
         *通过调用实现部分的具体方法实现具体的功能
         */
        public void operation(){
            mImplementor.operationImpl();
        }
    }
    
    • 抽象部分的完善
    public class RefinedAbstraction extends Abstraction{
        /**
         * 构造方法
         *
         * @param implementor
         */
        public RefinedAbstraction(Implementor implementor) {
            super(implementor);
        }
    
        /**
         * 对父类抽象部分的方法进行扩展
         */
        public void refinedOperation(){
    
        }
    
    }
    

    三 实例

    我们以生活中特别贴切的买奶茶为例,我们去奶茶店买奶茶,一般分为四种:大杯加糖、大杯不加糖、小杯加糖、小杯不加糖,所以对于一杯奶茶来说,这四种变化实质上就只有两种变化,一是大小杯,而是加糖不加糖。两种维度可以独立变化。
    这里有两个维度,我们选取往奶茶里添不添东西作为实现部分,把大小杯作为抽象部分,反过来也是可以的,模式中定义的“抽象”与“实现”,本质上是两个独立变化的维度。

    • 实现部分
    /*
     * 实现部分
     * @author Jackson
     * @version 1.0.0
     * since 2019 03 05
     */
    public abstract class MilkTeaAddtives {
    
        /**
         * 具体往奶茶里添加什么,由子类实现
         * @return
         */
        public abstract String addSomething();
    }
    
    • 实现部分的具体实现一,加糖
    /*
     * 实现部分的具体实现,加糖
     * @author Jackson
     * @version 1.0.0
     * since 2019 03 06
     */
    public class SugerAddMilkTea extends MilkTeaAddtives{
        @Override
        public String addSomething() {
            return "加糖";
        }
    }
    
    • 实现部分的具体实现二,原味
    /*
     * 实现部分的具体实现二 ,普通
     * @author Jackson
     * @version 1.0.0
     * since 2019 03 06
     */
    public class OrdinaryMilkTea extends MilkTeaAddtives{
        @Override
        public String addSomething() {
            return "原味";
        }
    }
    
    • 抽象部分,要有一个对实现部分对象的引用,具体做什么由其子类完善
    /*
     * 抽象部分
     * @author Jackson
     * @version 1.0.0
     * since 2019 03 05
     */
    public abstract class MilkTea {
    
        protected MilkTeaAddtives mMilkTeaAddtives;  // 声明一个实现部分对象的引用
    
        /**
         * 构造方法
         * @param milkTeaAddtives
         */
        public MilkTea(MilkTeaAddtives milkTeaAddtives) {
            this.mMilkTeaAddtives = milkTeaAddtives;
        }
    
        /**
         * 具体什么样的奶茶由子类决定
         */
        public abstract void makeMilkTea();
    
    
    }
    
    • 抽象部分的完善一,大杯
    public class LargeMilkTea extends MilkTea{
        /**
         * 构造方法
         *
         * @param milkTeaAddtives
         */
        public LargeMilkTea(MilkTeaAddtives milkTeaAddtives) {
            super(milkTeaAddtives);
        }
    
        @Override
        public void makeMilkTea() {
            System.out.println("大杯的"+mMilkTeaAddtives.addSomething()+"奶茶");
        }
    }
    
    • 抽象部分的完善二 ,小杯
    public class SmallMilkTea extends MilkTea{
        /**
         * 构造方法
         *
         * @param milkTeaAddtives
         */
        public SmallMilkTea(MilkTeaAddtives milkTeaAddtives) {
            super(milkTeaAddtives);
        }
    
        @Override
        public void makeMilkTea() {
            System.out.println("小杯的"+mMilkTeaAddtives.addSomething()+"奶茶");
        }
    }
    
    • 测试代码
     // 原味的
            OrdinaryMilkTea ordinaryMilkTea=new OrdinaryMilkTea();
            // 加糖
            SugerAddMilkTea sugerAddMilkTea=new SugerAddMilkTea();
    
            // 大杯原味
            LargeMilkTea largeMilkTeaOrdinary=new LargeMilkTea(ordinaryMilkTea);
            largeMilkTeaOrdinary.makeMilkTea();
    
            // 大杯加糖
            LargeMilkTea largeMilkTeaSuger=new LargeMilkTea(sugerAddMilkTea);
            largeMilkTeaSuger.makeMilkTea();
    
            // 小杯原味
            SmallMilkTea smallMilkTeaOrdinary=new SmallMilkTea(ordinaryMilkTea);
            smallMilkTeaOrdinary.makeMilkTea();
    
            // 小杯加糖
            SmallMilkTea smallMilkTeaSuger=new SmallMilkTea(sugerAddMilkTea);
            smallMilkTeaSuger.makeMilkTea();
    
    • 运行结果


    桥接模式具有良好的扩展性,因为桥接模式的两个维度独立变化的,比如,如果我们现在想扩展一下,新增中杯的奶茶,只需新增一种抽象部分的实现模式即可。

    • 中杯奶茶的抽象部分的完善
    public class MiddleMilkTea extends MilkTea{
        /**
         * 构造方法
         *
         * @param milkTeaAddtives
         */
        public MiddleMilkTea(MilkTeaAddtives milkTeaAddtives) {
            super(milkTeaAddtives);
        }
    
        @Override
        public void makeMilkTea() {
            System.out.println("中杯的"+mMilkTeaAddtives.addSomething()+"奶茶");
        }
    }
    
    • 测试代码
      //中杯原味
       MiddleMilkTea middleMilkTeaOrdinary=new MiddleMilkTea(ordinaryMilkTea);
      middleMilkTeaOrdinary.makeMilkTea();
    
      // 中杯加糖
       MiddleMilkTea middleMilkTeaSuger=new MiddleMilkTea(sugerAddMilkTea);
       middleMilkTeaSuger.makeMilkTea();
    

    运行结果就不在这里展示了。
    同样,如果要增加口味,也可以让实现部分变化起来,比如,加珍珠,加蓝莓等等,这里就不一一举例了。
    可以看出,不管是口味(MilkTeaAddtives)的变化,还是大小杯(MilkTea)的变化,都是独立的,没有交集,两者唯一的联系是MilkTea中保持对MilkTeaAddtives的引用,此为两者的纽带,这就是桥接模式。

    四 优点

    桥接模式主要有以下几个优点

    • 抽象和实现分离,这也是桥接模式的主要特点,该模式让抽象部分和实现部分独立开来,分别定义接口,极大地提高了系统的灵活性。
    • 更好的扩展性
      由于桥接模式把抽象和现实分离开了,这就使得抽象部分和实现部分可以独立地扩展而不会相互影响。
    • 可减少子类的个数,对于有两个维度的变化,如果采用继承的方式,子类的数量大约是两个维度乘积,采用桥接模式可以大幅度减少子类的个数。

    五 使用场景

    • 如果不希望抽象部分和实现部分采用固定的绑定关系,可以使用桥接模式。
    • 如果出现抽象部分和实现部分都能扩展的情况,可以采用桥接模式,让抽象部分和实现部分独立地变化。
    • 如果采用了继承会导致产生很多子类,可以考虑采用桥接模式,分析变化的原因,看看能否分离出不同的维度,然后通过桥接模式连接。

    相关文章

      网友评论

        本文标题:桥接模式

        本文链接:https://www.haomeiwen.com/subject/jsdwyqtx.html