【深入理解设计模式】桥接设计模式

桥接设计模式

桥接设计模式是一种结构型设计模式,它旨在将抽象部分与实现部分分离,使它们可以独立变化,从而更好地管理复杂性。桥接模式通常涉及多个层次的抽象,其中一个层次(通常称为"抽象")依赖于另一个层次(通常称为"实现")的实例。

定义:

​ 将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

结构:

  • 抽象化(Abstraction)角色 :定义抽象类,并包含一个对实现化对象的引用。
  • 扩展抽象化(Refined Abstraction)角色 :是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
  • 实现化(Implementor)角色 :定义实现化角色的接口,供扩展抽象化角色调用,它可以是一个接口或一个抽象类。实现并不一定要与抽象完全匹配,但必须提供抽象所需的方法。
  • 具体实现化(Concrete Implementor)角色 :给出实现化角色接口的具体实现。

案例一:

java 复制代码
// 实现部分接口
interface DrawingAPI {
    void drawCircle(double x, double y, double radius);
}

// 具体实现部分A
class DrawingAPI1 implements DrawingAPI {
    @Override
    public void drawCircle(double x, double y, double radius) {
        System.out.printf("API1.drawCircle at %f:%f radius %f%n", x, y, radius);
    }
}

// 具体实现部分B
class DrawingAPI2 implements DrawingAPI {
    @Override
    public void drawCircle(double x, double y, double radius) {
        System.out.printf("API2.drawCircle at %f:%f radius %f%n", x, y, radius);
    }
}

// 抽象部分
abstract class Shape {
    protected DrawingAPI drawingAPI;

    protected Shape(DrawingAPI drawingAPI) {
        this.drawingAPI = drawingAPI;
    }

    public abstract void draw();
}

// 扩充抽象部分
class Circle extends Shape {
    private double x, y, radius;

    public Circle(double x, double y, double radius, DrawingAPI drawingAPI) {
        super(drawingAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        drawingAPI.drawCircle(x, y, radius);
    }
}

public class BridgePatternExample {
    public static void main(String[] args) {
        // 使用实现部分A来画一个圆
        Shape circle = new Circle(1, 2, 3, new DrawingAPI1());
        circle.draw();

        // 使用实现部分B来画一个圆
        Shape anotherCircle = new Circle(5, 7, 11, new DrawingAPI2());
        anotherCircle.draw();
    }
}

在上面的示例中,DrawingAPI 接口代表了实现部分,DrawingAPI1DrawingAPI2 分别是具体的实现部分。Shape 是抽象部分,Circle 是扩充抽象部分。在 Circle 类中,通过 drawingAPI 调用实现部分的方法来绘制圆。在 BridgePatternExample 类的 main 方法中,我们可以看到如何使用不同的实现部分来绘制不同的圆。

案例二:

【例】视频播放器

需要开发一个跨平台视频播放器,可以在不同操作系统平台(如Windows、Mac、Linux等)上播放多种格式的视频文件,常见的视频格式包括RMVB、AVI、WMV等。该播放器包含了两个维度,适合使用桥接模式。

类图如下:

java 复制代码
/**
 * @author OldGj 2024/02/26
 * @version v1.0
 * @apiNote 视频文件 - 抽象实现化角色
 */
public interface VideoFile {

    public void decode(String fileName);

}
java 复制代码
/**
 * @author OldGj 2024/02/26
 * @version v1.0
 * @apiNote RMVB类型的视频文件  - 具体实现化角色
 */
public class RMVBFile implements VideoFile {
    @Override
    public void decode(String fileName) {
        System.out.println("rmvb: " + fileName);
    }
}
java 复制代码
/**
 * @author OldGj 2024/02/26
 * @version v1.0
 * @apiNote Avi格式的视频文件 - 具体实现化角色
 */
public class AVIFile implements VideoFile{
    @Override
    public void decode(String fileName) {
        System.out.println("avi : "+fileName);
    }
}
java 复制代码
/**
 * @author OldGj 2024/02/26
 * @version v1.0
 * @apiNote 操作系统类 - 抽象化角色
 */
public abstract class OperatingSystemVersion {
	//维护一个对实现的引用
    protected VideoFile videoFile;

    public OperatingSystemVersion(VideoFile videoFile) {
        this.videoFile = videoFile;
    }

    public abstract void play(String fileName);
}
java 复制代码
/**
 * @author OldGj 2024/02/26
 * @version v1.0
 * @apiNote MAC操作系统 - 扩展抽象化角色
 */
public class Mac extends OperatingSystemVersion{
    public Mac(VideoFile videoFile) {
        super(videoFile);
    }

    @Override
    public void play(String fileName) {
        System.out.println("mac");
        videoFile.decode(fileName);
    }
}
java 复制代码
/**
 * @author OldGj 2024/02/26
 * @version v1.0
 * @apiNote window操作系统 - 扩展抽象化角色
 */
public class Window extends OperatingSystemVersion{

    public Window(VideoFile videoFile) {
        super(videoFile);
    }

    @Override
    public void play(String fileName) {
        System.out.println("window");
        videoFile.decode(fileName);
    }
}
java 复制代码
/**
 * @author OldGj 2024/02/26
 * @version v1.0
 * @apiNote 客户端 - 测试类
 */
public class Client {
    public static void main(String[] args) {
        OperatingSystemVersion systemVersion = new Window(new RMVBFile());
        systemVersion.play("战狼");
    }
}

桥接模式是如何进行分离抽象和实现的?

假设我们要设计一个画图应用程序,它可以在不同的平台上绘制不同的形状,比如在 Windows 平台上绘制矩形和圆形,在 Linux 平台上绘制矩形和椭圆形。

首先,我们定义两个抽象类:ShapeDrawingAPI

java 复制代码
// 抽象类 Shape
abstract class Shape {
    protected DrawingAPI drawingAPI;

    protected Shape(DrawingAPI drawingAPI) {
        this.drawingAPI = drawingAPI;
    }

    public abstract void draw(); // 抽象方法,绘制形状
}

// 抽象类 DrawingAPI
interface DrawingAPI {
    void drawShape(); // 抽象方法,绘制形状
}

然后,我们定义具体的形状类,比如矩形和圆形,并且实现了 Shape 抽象类。

java 复制代码
// 具体形状类 Rectangle
class Rectangle extends Shape {
    public Rectangle(DrawingAPI drawingAPI) {
        super(drawingAPI);
    }

    @Override
    public void draw() {
        drawingAPI.drawShape(); // 调用实现部分的绘制方法
    }
}

// 具体形状类 Circle
class Circle extends Shape {
    public Circle(DrawingAPI drawingAPI) {
        super(drawingAPI);
    }

    @Override
    public void draw() {
        drawingAPI.drawShape(); // 调用实现部分的绘制方法
    }
}

接下来,我们实现两个不同的绘制API,比如在 Windows 平台和 Linux 平台上的绘制。

java 复制代码
// 具体实现部分 DrawingAPI for Windows
class DrawingAPIWindows implements DrawingAPI {
    @Override
    public void drawShape() {
        System.out.println("Drawing shape on Windows platform");
    }
}

// 具体实现部分 DrawingAPI for Linux
class DrawingAPILinux implements DrawingAPI {
    @Override
    public void drawShape() {
        System.out.println("Drawing shape on Linux platform");
    }
}

最后,我们在客户端代码中使用桥接模式来创建对象并调用方法。

java 复制代码
public class BridgePatternExample {
    public static void main(String[] args) {
        // 在 Windows 平台上绘制矩形
        Shape rectangleWindows = new Rectangle(new DrawingAPIWindows());
        rectangleWindows.draw();

        // 在 Linux 平台上绘制圆形
        Shape circleLinux = new Circle(new DrawingAPILinux());
        circleLinux.draw();
    }
}

在这个例子中,抽象部分是 Shape 抽象类,具体形状类 RectangleCircle 是扩充抽象部分。实现部分是 DrawingAPI 接口,具体实现部分 DrawingAPIWindowsDrawingAPILinux 分别是不同平台上的具体实现。

通过使用桥接模式,我们成功地将抽象部分和实现部分分离开来,使它们可以独立变化。例如,如果要在 Windows 平台上绘制其他形状,只需创建一个新的具体形状类,并提供相应的 DrawingAPIWindows 实现即可,而不需要修改现有的代码。这种设计使得系统更加灵活、可扩展和易于维护。

桥接模式的优点包括:

  • 分离抽象和实现,使得它们可以独立变化,降低了系统的耦合度。
  • 提高了系统的可扩展性,可以方便地增加新的抽象和实现。
  • 提高了系统的可维护性,通过分离抽象和实现,减少了修改一个层次对另一个层次的影响。

使用场景

  • 当一个类存在两个独立变化的维度 ,且这两个维度都需要进行扩展时
  • 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
  • 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
相关推荐
oioihoii几秒前
设计模式概述
java·c++·设计模式·面试·c#·大学必学
jjjxxxhhh1233 分钟前
c++设计模式之桥接模式
c++·设计模式·桥接模式
清灵xmf27 分钟前
为什么 Vue3 封装 Table 组件丢失 expose 方法呢?
开发语言·前端·javascript·封装·eltable
神仙别闹38 分钟前
基于JAVA实现的(GUI)坦克大战游戏
java·开发语言·游戏
凡人的AI工具箱1 小时前
15分钟学 Go 第 54 天 :项目总结与经验分享
开发语言·人工智能·后端·算法·golang
小春学渗透1 小时前
DAY110代码审计-PHP框架开发篇&ThinkPHP&版本缺陷&不安全写法&路由访问&利用链
开发语言·安全·web安全·php
R-sz1 小时前
java如何利用流式计算筛选出同一天时间最新的一条数据
java·windows·python
奈葵1 小时前
C语言字符函数和字符串函数
c语言·开发语言
程序员阿龙1 小时前
基于Spring Boot的在线性格测试系统设计与实现(源码+定制+开发)智能性格测试与用户个性分析平台、在线心理测评系统的开发、性格测试与个性数据管理系统
java·spring boot·后端·性格测评平台开发·用户性格测评系统·个性分析与推荐系统·心理测评与数据分析
robin_suli1 小时前
Java多线程八股(一), 锁策略,synchronized锁策略详解
java·开发语言·八股