桥接模式(Bridge Pattern)-(最通俗易懂的案例)

1.定义

桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。

问题:
这里的抽象与实现是什么意思呢?先来看一个例子:
假如你有一个几何形状Shape类,从它能扩展出两个子类: ​ 圆形Circle和 方形Square 。 你希望对这样的类层次结构进行扩展以使其包含颜色,所以你打算创建名为红色Red和蓝色Blue的形状子类。 但是, 由于你已有两个子类, 所以总共需要创建四个类才能覆盖所有组合, 例如 蓝色圆形Blue­Circle和 红色方形Red­Square 。
桥接模式(Bridge Pattern)-(最通俗易懂的案例)_第1张图片
在层次结构中新增形状和颜色将导致代码复杂程度指数增长。 例如添加三角形状, 你需要新增两个子类, 也就是每种颜色一个; 此后新增一种新颜色需要新增三个子类, 即每种形状一个。 照这样下去,所有组合类的数量将以几何级数增长,情况会越来越糟糕。

解决方案:
问题的根本原因在于我们试图在两个独立的维度——形状与颜色上进行扩展。这在处理继承时是很常见的问题。

桥接模式 通过将继承改为组合的方式来解决这个问题。 具体来说, 就是抽取其中一个维度并使之成为独立的类层次, 这样就可以在初始类中引用这个新层次的对象, 从而使得一个类不必拥有所有的状态和行为。
桥接模式(Bridge Pattern)-(最通俗易懂的案例)_第2张图片
根据该方法, 我们可以将颜色相关的代码抽取到拥有 红色和 蓝色两个子类的颜色类中, 然后在 形状类中添加一个指向某一颜色对象的引用成员变量。 现在, 形状类可以将所有与颜色相关的工作委派给连入的颜色对象。 这样的引用就成为了 形状和 颜色之间的桥梁。 此后, 新增颜色将不再需要修改形状的类层次, 反之亦然。

2.适用环境

  • 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
  • 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  • 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

3.模式结构图

桥接模式(Bridge Pattern)-(最通俗易懂的案例)_第3张图片
其中包含如下角色:

  • Abstraction(抽象类):用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义了一个 Implementor(实现类接口)类型的对象并可以维护该对象,它与 Implementor 之间具有关联关系。
  • RefinedAbstraction(提炼抽象类):扩充由 Abstraction 定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在 Abstraction 中声明的抽象业务方法,在 RefinedAbstraction 中可以调用在 Implementor 中定义的业务方法。
  • Implementor(实现类接口):定义实现类的接口,这个接口不一定要与 Abstraction 的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor 接口仅提供基本操作,而 Abstraction 定义的接口可能会做更多更复杂的操作。Implementor 接口对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,在 Abstraction 中不仅拥有自己的方法,还可以调用到 Implementor 中定义的方法,使用关联关系来替代继承关系。
  • ConcreteImplementor(具体实现类):具体实现 Implementor 接口,在不同的 ConcreteImplementor 中提供基本操作的不同实现,在程序运行时,ConcreteImplementor 对象将替换其父类对象,提供给抽象类具体的业务操作方法。

4.实例

我们就以上述形状与颜色这两个独立的维度来实现给不同的形状刷上不同颜色的例子来讲解:
ColorAPI :用于画各种颜色的接口

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public interface ColorAPI {
    public void paint();
}

BlueColorAPI :画蓝色的实现类

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public class BlueColorAPI implements ColorAPI {
    @Override
    public void paint() {
        System.out.println("画上蓝色");
    }
}

RedColorAPI :画红色的实现类

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public class RedColorAPI implements ColorAPI
{
    @Override
    public void paint() {
        System.out.println("画上红色");
    }
}

Shape :抽象形状类

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public abstract class Shape {
    protected ColorAPI colorAPI;    //添加一个颜色的成员变量以调用ColorAPI 的方法来实现给不同的形状上色

    public void setDrawAPI(ColorAPI colorAPI) {      //注入颜色成员变量
        this.colorAPI= colorAPI;
    }
 
    public abstract void draw();        
}

Circle :圆形类

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public class Circle extends Shape {
    @Override
    public void draw() {
        System.out.print("我是圆形");
        colorAPI.paint();
    }
}

Rectangle :长方形类

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public class Rectangle extends Shape {
    @Override
    public void draw() {
        System.out.print("我是长方形");
        colorAPI.paint();
    }
}

Client:客户端

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public class Client {

    public static void main(String[] args) {
        //创建一个圆形
        Shape shape = new Circle();
        //给圆形蓝色的颜料
        shape.setDrawAPI(new BlueColorAPI());
        //上色
        shape.draw();


        //创建一个长方形
        Shape shape1 = new Rectangle();
        //给长方形红色的颜料
        shape1.setDrawAPI(new RedColorAPI());
        //上色
        shape1.draw();

    }
}

打印输出:

我是圆形画上蓝色
我是长方形画上红色

假如现在客户让我们增了一个三角形,我们只需要新增一个三角形类就可以了,而无需把每一种颜色都增加一个,我们在客户端调用时只需按照需求来挑选即可:

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("我是三角形");
        colorAPI.paint();
    }
}

增加颜色也是一样,我们只需要增加一个新的颜色并实现ColorAPI的接口即可,而无需更改类的层次,例如增加一个绿色:

/**
 * Created on 2020/3/18
 * Package com.design_pattern.bridge
 *
 * @author dsy
 */
public class GreenColorAPI implements ColorAPI {
    @Override
    public void paint() {
        System.out.println("画上绿色");
    }
}

现在再来看“将抽象部分与他的实现部分分离”这句话,实际上就是在说实现系统可能有多个角度分类(例如例子中的形状与颜色),每一种分类都有可能变化,那么把这种多角度分离出来让他们独立变化,减少他们之间的耦合。

5.优缺点分析

优点:

  • 实现抽象和实现的分离
  • 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统
  • 桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差,而且多继承结构中类的个数非常庞大,桥接模式是比多继承方案更好的解决方法

缺点:

  • 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
  • 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。

你可能感兴趣的:(设计模式,设计模式,java)