1 定义

桥接模式:将抽象部分与其实现部分分离,使它们都可以独立地变化。
它是一种对象结构型模式,又称为柄体模式或者接口模式。

2 概述

桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统变得更加符合SRP。

比如,设计一个跨平台的图像浏览系统,支持的图片格式包括:

  • PNG
  • BMP
  • JPG
  • GIF

等等,而支持的系统包括:

  • Windows
  • Unix
  • Linux

等等,这样,系统与图片格式就是两个不同的维度,可以利用桥接模式将这两个维度分离,使得它们可以独立变化,增加新的图片格式或者新的系统时,都不会对另一个维度造成任何影响。

3 角色

  • Abstraction(抽象类):用于定义抽象类的接口,一般是抽象类而不是接口,具有一个Implementor的成员,与Implementor为关联关系,既可以包含抽象的业务方法,也可以包含具体业务方法
  • RefinedAbstraction(扩充抽象类):扩充由Abstraction定义的接口,通常为具体类,实现了在Abstraction中的抽象业务方法,同时可以调用Implementor中的业务方法
  • Implementor(实现类接口):实现类的接口,相比起Abstractoin提供的更多更复杂的操作,Implementor一般只提供基本操作,具体实现交由子类处理
  • ConcreteImplementor(具体实现类):具体实现Implementor接口,不同的ConcreteImplementor提供不同实现的基本操作

结构图如下:
设计模式学习笔记(十):桥接模式_第1张图片

4 步骤

  • 识别维度:首先识别出系统中两个独立变化的维度
  • 继承:识别出维度后,将它们设计为两个独立的继承等级结构,比如上面的图片格式以及系统,将图片格式与系统设为抽象层,而BMP,GIF等继承图片格式抽象层,Windows等具体系统集成系统抽象层
  • 建立抽象耦合:在抽象层建立一个抽象关联
  • 扩展:建立抽象耦合后,根据需要对两个维度进行独立扩展,比如增加新的图片格式WBEP,增加新的操作系统Mac等

5 实例

跨平台的图片浏览系统,支持的图片格式包括PNG,JPG,BMP,GIF等,支持的系统包括Linux,Unix,Windows等,使用桥接模式设计。

  • 图片维度:抽象类Image,BMP,GIF等继承ImageImage具有一个ImageShow的成员变量
  • 系统维度:Linux,Unix,Windows实现图片显示接口ImageShow

代码如下:

public class Test
{
    public static void main(String[] args) {
        Image image = new GIF();
        image.setImageShow(new Linux());
        image.show();
    }
}

//Image抽象类
abstract class Image
{
    protected ImageShow imageShow;
    public void setImageShow(ImageShow imageShow)
    {
        this.imageShow = imageShow;
    }
    public abstract show();
}

class BMP extends Image
{
    @Override
    public void show()
    {
        imageShow.show("BMP");
    }
}

class GIF extends Image
{
    @Override
    public void show()
    {
        imageShow.show("GIF");
    }
}

class PNG extends Image
{
    @Override
    public void show()
    {
        imageShow.show("PNG");
    }
}

class JPG extends Image
{
    @Override
    public void show()
    {
        imageShow.show("JPG");
    }
}

//图片显示接口
interface ImageShow
{
    void show(String name);
}

class Windows implements ImageShow
{
    @Override
    public void show(String name)
    {
        System.out.println("Windows show "+name);
    }
}

class Linux implements ImageShow
{
    @Override
    public void show(String name)
    {
        System.out.println("Linux show "+name);
    }
}

class Unix implements ImageShow
{
    @Override
    public void show(String name)
    {
        System.out.println("Unix show "+name);
    }
}

更换图片格式只需要修改Image的父类:

Image image = new GIF();
Image image = new BMP();
Image image = new JPG();
Image image = new PNG();

而更换操作系统只需要修改传入setter的参数:

image.setImageShow(new Linux());
image.setImageShow(new Windows());
image.setImageShow(new Unix());

这样就可以把图片以及系统两个维度分离,并能够独立扩展,增加新的图片格式,只需要增加一个新的继承Image的类即可,增加新的系统只需实现ImageShow接口即可。
由于例子简单使用反射进行简化代码并增加了新的系统以及图片格式,代码如下:

public class Test
{
    public static void main(String[] args) {
        Image image = new WBEP();
        image.setImageShow(new Mac());
        image.show();
    }
}

abstract class Image
{
    protected ImageShow imageShow;
    public void setImageShow(ImageShow imageShow)
    {
        this.imageShow = imageShow;
    }
    public void show()
    {
        imageShow.show(getClass().getName());
    }
}

class BMP extends Image{}
class GIF extends Image{}
class PNG extends Image{}
class JPG extends Image{}
class WBEP extends Image{}

interface ImageShow
{
    void show(String name);
}

abstract class ImageSystem implements ImageShow
{
    public void show(String name)
    {
        System.out.println(getClass().getName()+" show "+name);
    }
}

class Windows extends ImageSystem{}
class Linux extends ImageSystem{}
class Unix extends ImageSystem{}
class Mac extends ImageSystem{}

6 主要优点

  • 低耦合:分离抽象接口及其实现部分,桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以按照各自的维度变化。也就是说,抽象和实现不再同一个继承层次中,而是让抽象作为父类,实现作为子类,这样就可以任意组合子类,从而获得多维度的组合对象
  • 取代多重继承:很多情况下桥接模式可以取代多重继承,多重继承违反了SRP(单一权责原则),复用性差,而且类的个数多,桥接模式可以有效减少子类个数
  • 提高扩展性:桥接模式提高了系统的扩展性,在两个维度中任意扩展一个维度,都不需要修改原有系统,符合开闭原则

    7 主要缺点

  • 增加理解难度:桥接模式会增加系统的理解以及设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计以及编程
  • 需要正确识别抽象层:桥接模式要求正确识别系统中两个独立变化的维度,因此适用范围有一定局限,正确识别独立维度需要一定经验积累

    8 适用场景

  • 如果一个系统需要在抽象类和具体类之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系
  • 抽象部分和实现部分可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象类子类的对象和一个实现类子类的对象进行动态组合
  • 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展
  • 对于不希望使用继承或因为多重继承导致系统类的个数急剧增加的系统

    9 总结

    设计模式学习笔记(十):桥接模式_第2张图片