1. 定义
将抽象部分与其实现部分分离,使得它们可以独立地变化,它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式
2. 桥接模式结构图:
结构图中角色分析
- Abstraction(抽象类):一般是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,包含抽象业务方法,也可以包含具体的业务方法
- RefinedAbstraction(扩充抽象类):扩充由Abstraction定义的接口,一般是具体类,实现了Abstraction中声明的抽象业务方法,在RefinedAbstraction中可以调用在Implementor中定义的业务方法
- Implementor(实现类接口):定义实现类接口,不一定要与Abstraction完全一致,可以完全不同,Implementor接口仅提供基本操作,Abstraction定义了更多操作的接口,还可以调用到Implementor中定义的方法
- ConcreteImplementor(具体实现类):具体实现Implementor
3. 核心代码
interface Implementor{
public void operationImpl();
}
abstract class Abstraction {
protercted Implementor impl; //定义实现类接口对象
public void setImpl(Implementor impl){
this.impl = impl;
}
public abstract void operation(); //声明抽象业务方法
}
//扩充抽象类
class RefinedAbstraction extends Abstraction {
public void operation(){
//业务代码
impl.operationImpl(); //调用实现类的方法
}
}
4. 案例
1) 方案结构图
2) 代码实现
//抽象图像类:抽象类
public abstract class Image {
protected ImageImp imp;
public void setImageImp(ImageImp imp){
this.imp = imp;
}
public abstract void parseFile(String fileName);
}
//抽象操作系统实现类:实现类接口
public interface ImageImp {
public void doPaint(Matrix m); //显示像素矩阵 m
}
//BMP格式图像:扩充抽象类
public class BMPImage extends Image {
@Override
public void parseFile(String fileName) {
//模拟解析BMP文件并获得一个像素矩阵对象m
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName +",格式为BMP");
}
}
//GIF格式图像:扩充抽象类
public class GIFImage extends Image {
@Override
public void parseFile(String fileName) {
//模拟解析GIF文件并获得一个像素矩阵对象m
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName +",格式为GIF");
}
}
//JPG格式图像:扩充抽象类
public class JPGImage extends Image {
@Override
public void parseFile(String fileName) {
//模拟解析JPG文件并获得一个像素矩阵对象m
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName +",格式为JPG");
}
}
//PNG格式图像:扩充抽象类
public class PNGImage extends Image {
@Override
public void parseFile(String fileName) {
//模拟解析PNG文件并获得一个像素矩阵对象m
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName +",格式为PNG");
}
}
//Linux操作系统实现类:具体实现类
public class LinuxImp implements ImageImp {
@Override
public void doPaint(Matrix m) {
//调用Linux系统的绘制函数绘制像素矩阵
System.out.println("在Linux操作系统中显示图像: ");
}
}
//Linux操作系统实现类:具体实现类
public class UnixImp implements ImageImp {
@Override
public void doPaint(Matrix m) {
// TODO Auto-generated method stub
//调用UNIX系统的绘制函数绘制像素矩阵
System.out.println("在UNIX操作系统中显示图像: ");
}
}
//windows操作系统实现类:具体实现类
public class WindowsImp implements ImageImp {
@Override
public void doPaint(Matrix m) {
//调用Windows系统的绘制函数绘制像素矩阵
System.out.println("在Windows操作系统中显示图像: ");
}
}
//像素矩阵类:辅助类,各种格式的文件最终都被转化为像素矩阵,不同的操作系统提供不同的方式
//显示像素矩阵
public class Matrix {
//此处代码省略
}
//客户端代码
public class Client {
public static void main(String[] args) {
//为了扩展性,可通过配置文件配置具体扩充抽象类和具体实现类
try {
Image image = (Image) Class.forName("com.zach.pattern.bridge.JPGImage").newInstance();
ImageImp imp = (ImageImp) Class.forName("com.zach.pattern.bridge.WindowsImp").newInstance();
image.setImageImp(imp);
image.parseFile("小龙女");
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
若要更换图像文件格式或者更换操作系统,只需修改配置文件即可,在实际使用时,可以通过分析图像文件格式后缀名来确定具体的文件格式,在程序运行时获取操作系统信息来确定操作系统,无需使用配置文件,当增加新的图像文件格式或者操作系统时,只需增加一哥对应的扩充抽象类或具体实现类即可;
5. 适配器模式与桥接模式联用
- 桥接模式用于系统初步设计,对于存在两个独立变化维度的类可以将其分为抽象类和实现类两个角色,使它们分别进行变化;
-
初步设计完成之后,当发现系统已有类无法协同工作时,可以采用适配器模式,特别是涉及大量第三方应用接口的情况
6. 桥接模式与适配器模式联合使用案例
7. 桥接模式总结
1) 优点
- 分离抽象接口及其实现部分
- 在很多情况下,桥接模式可以取代多层继承方案
- 提高系统扩展性
2) 缺点
- 关联关系建立在抽象层,要求一开始就针对抽象层进行设计与编程
- 桥接模式要求正确识别出系统中两个独立变化的维度,使用范围受限
3) 适用场景
- 若系统需要在抽象类和具体类之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系
- 抽象部分和实现部分可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象类子类的对象和一个实现类子类的对象进行组合,即系统需要对抽象类角色和实现类角色进行动态耦合
- 一个类存在两个以上独立变化的维度,且这多个维度都需要独立进行扩展
- 不希望使用继承或因多继承导致系统类的个数急剧增加的系统