GOF设计模式(04)桥接模式

简介

一、定义

1、概念

  • 桥接(Bridge)模式:将抽象部分与其实现部分分离,使得他们都可以独立地变化。它是一种对象结构型模式,又称为接口模式。桥接符合开闭原则和单一职责原则。

2、理解

  • 在使用桥接模式时,我们首先应该识别出一个类所具有的两个独立变化的维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合。通常情况下,我们将具有两个独立变化维度的类的一些普通业务方法和与之关系最密切的维度设计为“抽象类”层次结构(抽象部分),而将另一个维度设计为“实现类”层次结构(实现部分)。
  • 例如:对于毛笔而言,由于型号是其固有的维度,因此可以设计一个抽象的毛笔类,在该类中声明并部分实现毛笔的业务方法,而将各种型号的毛笔作为其子类;颜色是毛笔的另一个维度,由于它与毛笔之间存在一种“设置”的关系,因此我们可以提供一个抽象的颜色接口,而将具体的颜色作为实现该接口的子类。在此,型号可认为是毛笔的抽象部分,而颜色是毛笔的实现部分。

二、组件

  • Abstraction(抽象类):用于定义抽象类的接口,其中定义了一个实现了Implementor接口的对象并可以维护该对象,它与Implementor之间具有关联关系,它既可以包含抽象业务方法, 也可以包含具体业务方法。
  • RefinedAbstratction(扩充抽象类):扩充由Abstraction定义的接口,通常情况下他不再是抽象类而是具体类,实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中可以调用在Implementor中定义的业务方法。
  • Implementor(实现类接口):定义实现类的接口,一般而言,它不与Abstraction的接口一致。它只提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。
  • ConcreteImplementor(具体实现类):具体实现Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplentor将替换其父类对象,提供给抽象类具体的业务操作方法。

三、结构图(跨平台图像浏览系统)

 

示例

一、抽象部分

1、抽象类和扩充抽象类

//像素矩阵类:辅助类,各种格式的文件最终都被转化为像素矩阵,不同的操作系统提供不同的方式显示像素矩阵  
class Matrix {  
    //此处代码省略  
}  
  
//抽象图像类:抽象类  
abstract class Image {  
    protected ImageImp imp;  
  
    public void setImageImp(ImageImp imp) {  
        this.imp = imp;  
    }   
  
    public abstract void parseFile(String fileName);  
}  

//JPG格式图像:扩充抽象类  
class JPGImage extends Image {  
    public void parseFile(String fileName) {  
        //模拟解析JPG文件并获得一个像素矩阵对象m;  
        Matrix m = new Matrix();   
        imp.doPaint(m);  
        System.out.println(fileName + ",格式为JPG。");  
    }  
}  
  
//PNG格式图像:扩充抽象类  
class PNGImage extends Image {  
    public void parseFile(String fileName) {  
        //模拟解析PNG文件并获得一个像素矩阵对象m;  
        Matrix m = new Matrix();   
        imp.doPaint(m);  
        System.out.println(fileName + ",格式为PNG。");  
    }  
}  

二、实现部分

1、实现类接口和具体实现类

//抽象操作系统实现类:实现类接口  
interface ImageImp {  
    public void doPaint(Matrix m);  //显示像素矩阵m  
}   
  
//Windows操作系统实现类:具体实现类  
class WindowsImp implements ImageImp {  
    public void doPaint(Matrix m) {  
        //调用Windows系统的绘制函数绘制像素矩阵  
        System.out.print("在Windows操作系统中显示图像:");  
    }  
}  
  
//Linux操作系统实现类:具体实现类  
class LinuxImp implements ImageImp {  
    public void doPaint(Matrix m) {  
        //调用Linux系统的绘制函数绘制像素矩阵  
        System.out.print("在Linux操作系统中显示图像:");  
    }  
}  

2、测试代码

class Client {  
    public static void main(String args[]) {  
        Image image;  
        ImageImp imp;  
        image = new JPGImage();  
        imp = new WindowsImp();  
        image.setImageImp(imp);  
        image.parseFile("小龙女");  
    }  
}  

 

总结

一、优缺点

1、优点

  • 分离抽象接口及其实现部分 -> 桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度变化
  • 取代多层继承方案 -> 极大地减少了子类的个数
  • 提高了系统可扩展性 -> 在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合开闭原则

2、缺点

  • 增加了系统的理解和设计难度 -> 需要开发者在一开始就对抽象层进行设计与编程
  • 要求正确识别出系统中两个独立变化的维度 -> 如何正确地识别需要一定的经验积累

二、使用场景

  • 一个类存在两个(或者多个)独立变化的维度,而且这两个(或者多个)维度都需要独立进行扩展。
  • 不希望使用继承或因为多层继承而导致系统中类的个数急剧增加。
  • 一个系统需要在抽象类和具体类之间增加更多的灵活性,避免在两个层次之间建立静态继承关系,通过桥接可以使它们在抽象层建立一个关联关系。

三、适配器模式和桥接模式的联合使用

1、基本思想

  • 桥接模式感觉上和适配器模式的对象适配器感觉比较像,但是二者从思想和具体使用都存在不同;
  • 桥接模式和适配器模式用于设计的不同阶段,桥接模式用于系统的初步设计,对于存在两个独立变化维度的类可以将其分为抽象化和实现化两个角色,使它们可以分别进行变化;
  • 初步设计完成之后,当发现系统与已有类无法协同工作时,可以采用适配器模式;
  • 有时候在设计初期也需要考虑适配器模式,特别是那些涉及到大量第三方应用接口的情况;

2、使用举例

  • 在某系统的报表处理模块中,需要将报表显示数据采集分开,系统可以有多种报表显示方式也可以有多种数据采集方式,如可以从文本文件中读取数据,也可以从数据库中读取数据,还可以从Excel文件中获取数据。如果需要从Excel文件中获取数据,则需要调用与Excel相关的API,而这个API是现有系统所不具备的,该API由厂商提供。
  • 在设计过程中,由于存在报表显示和数据采集两个独立变化的维度,因此可以使用桥接模式进行初步设计;为了使用Excel相关的API来进行数据采集则需要使用适配器模式。

猜你喜欢

转载自www.cnblogs.com/stanwuc/p/10897900.html