桥接模式

一 定义

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

二 模式结构


角色介绍

  • 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的引用,此为两者的纽带,这就是桥接模式。

四 优点

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

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

五 使用场景

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

你可能感兴趣的:(桥接模式)