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

在这里插入图片描述

桥接设计模式

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

定义:

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

结构:

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

案例一:

// 实现部分接口
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等。该播放器包含了两个维度,适合使用桥接模式。

类图如下:

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

    public void decode(String fileName);

}
/**
 * @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);
    }
}
/**
 * @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);
    }
}
/**
 * @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);
}
/**
 * @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);
    }
}
/**
 * @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);
    }
}
/**
 * @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

// 抽象类 Shape
abstract class Shape {
    protected DrawingAPI drawingAPI;

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

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

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

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

// 具体形状类 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 平台上的绘制。

// 具体实现部分 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");
    }
}

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

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 实现即可,而不需要修改现有的代码。这种设计使得系统更加灵活、可扩展和易于维护。

桥接模式的优点包括:

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

使用场景

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/426294.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLO-World 简单无需标注无需训练直接可以使用的检测模型

参考: https://github.com/AILab-CVC/YOLO-World YOLO-World 常规的label基本不用训练,直接传入图片,然后写入文本label提示既可 案例demo: 1)官方提供 https://huggingface.co/spaces/stevengrove/YOLO-World https://huggingface.co/spaces/SkalskiP/YOLO-World 检测…

javaWebssh在线授课辅导系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh在线授课辅导系统是一套完善的web设计系统(系统采用ssh框架进行设计开发),对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用 B/S模式开发。开发环境为TOMCAT7.…

Spring框架学习

Spring: (1)Bean线程安全问题 (2)AOP,事务原理,事务失败 (3)Bean的生命周期 (4)循环依赖 SpringMVC: (1&#xff09…

技术小知识:面向对象和过程的区别 ⑤

一、思想区别 面相对象:始终把所有事情思考归类、抽离封装成对象来调用完成。 面向过程:直接平铺展开按顺序执行完成任务。 面向对象多了很多对象的创建、使用,销毁的过程资源消耗。是一种模块化编程思想。 https://www.cnblogs.com/kuangmen…

为何要使用流媒体服务器

安防系统中,我们偶尔会遇到“流媒体服务器”这个词,那么为什么需要这个服务呢? 视频监控 我们知道,监控摄像机的工作原理就是将自然界的光影,通过摄像机镜头对焦到“靶芯”(CMOS),实…

mysql8修改密码

mysql8.0修改密码 windows下忘了MySQL8.0的密码,可以通过以下方式修改。 1、管理员方式打开cmd命令窗口 输入: net stop mysql接着输入: mysqld --console --skip-grant-tables --shared-memory2、管理员方式打开另外一个cmd窗口 输入&…

nvm安装和使用保姆级教程(详细)

一、 nvm是什么 : nvm全英文也叫node.js version management,是一个nodejs的版本管理工具。nvm和npm都是node.js版本管理工具,为了解决node.js各种版本存在不兼容现象可以通过它可以安装和切换不同版本的node.js。 二、卸载之前安装的node: …

c++之通讯录管理系统

1,系统需求 通讯录是一个记录亲人,好友信息的工具 系统中需要实现的功能如下: 1,添加联系人:向通讯录中添加新人,信息包括(姓名,性别,年龄,联系电话&#…

基于SpringBoot的企业头条管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式 🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 &…

Libevent的使用及reactor模型

Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读…

深入理解抽象工厂模式:原理、应用与优缺点分析

文章目录 **一、模式原理****二、使用场景****三、为何使用抽象工厂模式**四、代码示例**五、优点与缺点****总结** 一、模式原理 ​ 抽象工厂模式是一种创建型设计模式,其核心思想在于通过抽象工厂接口提供一个创建一系列相关或相互依赖对象的接口,而不…

Rust结构体讲解学习,以及impl结构体方法和结构体关联函数

Rust 中的结构体(Struct)与元组(Tuple)都可以将若干个类型不一定相同的数据捆绑在一起形成整体,但结构体的每个成员和其本身都有一个名字,这样访问它成员的时候就不用记住下标了。元组常用于非定义的多值传…

十六、异常和File

异常和File 一、异常1.1异常的分类1.2 异常的作用1.3 异常的处理方式1.3.1 JVM默认的处理方式1.3.2 自己处理(捕获异常)1.3.3 自己处理(灵魂四问) 1.4 异常中的常见方法1.5 抛出异常综合练习(键盘录入数据)…

nginx-图片模块

./configure --with-http_image_filter_module location / {root html;index index.html index.htm;if ($arg_w "") {set $arg_w -;}if ($arg_h "") {set $arg_h -;}image_filter resize $arg_w $arg_h;image_filter_jpeg_quality 95; } 访问: 1234…

xxl-job--02--可视化界面各功能详细介绍

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 可视化界面1 新增执行器2.新增任务**执行器**:**任务描述**:**路由策略**:**Cron**:cron表达式**运行模式**JobHandl…

Python把excel内容保存为图片(非统计图而是纯原表格数据)

一、引入 excel2img 库,没有的话使用 pip install excel2img进行安装 二、采用如下方法进行图片生成 excel文件名为:111.xlsx excel表格里面的sheet名称列表为 [Sheet1, Sheet2] 最终保存为以sheet名称.png的图片 支持跨表格合并项 import excel2i…

一文扫盲:室内导航系统的应用场景和技术实现(入门级)

hello,我是贝格前端工场,之间搞过一些室内导航项目,有2D也有3D的,算是有些经验,这里给大家分享一下室内导航的基本尝试,欢迎老铁们点赞、关注,如有需求可以私信我们。 一、室内导航是什么 室内…

理解这几个安全漏洞,你也能做安全测试

01 短信炸弹 1、漏洞描述 短信轰炸攻击是常见的一种攻击,攻击者通过网站页面中所提供的发送短信验证码的功能处,通过对其发送数据包的获取后,进行重放,如果服务器短信平台未做校验的情况时,系统会一直去发送短信&…

高斯消元法的应用

如果有这么一个线性规划系统的例子: 添加图片注释,不超过 140 字(可选) 将如上的线性规划系统转换为: 添加图片注释,不超过 140 字(可选) 这里要注意的是转换后的约束条件全部都变…

模版进阶C++

非类型模版 之前我们写的模版都是在不知道模版(类)中有的变量的类型是什么的时候,我们先用模版参数定义,当类实例化的时候在传参确认 非类型模版:模版参数定义的时候也可以定义整型类型(c20之后才支持其…