软件设计模式系列之九——桥接模式

1 模式的定义

桥接模式是一种结构型设计模式,它用于将抽象部分与其实现部分分离,以便它们可以独立地变化。这种模式涉及一个接口,它充当一个桥,使得具体类可以在不影响客户端代码的情况下改变。桥接模式将继承关系转化为组合关系,从而减少类之间的紧密耦合度,使得系统更加灵活和可扩展。

桥接模式的核心思想是将系统中的多个维度的变化解耦,使得每个维度可以独立地扩展和修改,而不会影响到其他维度。这使得系统更加灵活,易于维护和扩展。桥接模式通常应用于需要处理多个变化维度的场景,如不同操作系统和应用程序之间的通信、多种格式和不同设备的兼容性等。

2 举例说明

让我们通过一个简单的例子来说明桥接模式。
在这里插入图片描述

比如在视频播放器的场景中,我们可以使用桥接模式来处理两个独立变化的维度:视频格式和操作系统。视频格式维度包括FLV、AVI、MP4等不同的视频格式,操作系统维度包括Windows、Linux、macOS、Android等不同的操作系统。通过桥接模式,我们可以创建具有不同视频格式和运行在不同操作系统上的播放器,同时保持代码的可扩展性和可维护性。这意味着我们可以轻松地添加新的视频格式和支持新的操作系统,而不会对现有代码造成影响。

3 结构

桥接模式的结构包括以下几个关键组件:
在这里插入图片描述

抽象类(Abstraction):定义抽象部分的接口,维护一个指向实现部分的引用。
扩展抽象类(Refined Abstraction):扩展抽象类,实现更多特定功能。
实现接口(Implementor):定义实现部分的接口,通常包括具体操作的方法。
具体实现类(Concrete Implementor):实现接口的具体实现。

4 实现步骤

桥接模式的实现步骤如下:

定义实现接口(Implementor),并在其中声明抽象方法。
创建具体实现类(Concrete Implementor),实现实现接口中的方法。
定义抽象类(Abstraction),包含一个指向实现接口的引用,并在其中定义抽象方法。
创建扩展抽象类(Refined Abstraction),继承抽象类,并实现具体功能,可以调用实现接口中的方法。
在客户端代码中使用抽象类和具体实现类。

5 代码实现

// 实现接口 - 视频播放器实现
interface VideoPlayerImplementor {void playVideo();
}// 具体实现类 - 不同视频格式的播放器
class FLVVideoPlayer implements VideoPlayerImplementor {public void playVideo() {System.out.println("播放FLV格式的视频。");}
}class AVIVideoPlayer implements VideoPlayerImplementor {public void playVideo() {System.out.println("播放AVI格式的视频。");}
}class MP4VideoPlayer implements VideoPlayerImplementor {public void playVideo() {System.out.println("播放MP4格式的视频。");}
}// 抽象类 - 视频播放器
abstract class VideoPlayer {protected VideoPlayerImplementor implementor;public VideoPlayer(VideoPlayerImplementor implementor) {this.implementor = implementor;}public abstract void play();
}// 扩展抽象类 - 不同操作系统上的视频播放器
class WindowsVideoPlayer extends VideoPlayer {public WindowsVideoPlayer(VideoPlayerImplementor implementor) {super(implementor);}public void play() {System.out.println("在Windows系统上播放视频:");implementor.playVideo();}
}class LinuxVideoPlayer extends VideoPlayer {public LinuxVideoPlayer(VideoPlayerImplementor implementor) {super(implementor);}public void play() {System.out.println("在Linux系统上播放视频:");implementor.playVideo();}
}class MacOSVideoPlayer extends VideoPlayer {public MacOSVideoPlayer(VideoPlayerImplementor implementor) {super(implementor);}public void play() {System.out.println("在macOS系统上播放视频:");implementor.playVideo();}
}class AndroidVideoPlayer extends VideoPlayer {public AndroidVideoPlayer(VideoPlayerImplementor implementor) {super(implementor);}public void play() {System.out.println("在Android系统上播放视频:");implementor.playVideo();}
}public class Client {public static void main(String[] args) {VideoPlayerImplementor flvPlayer = new FLVVideoPlayer();VideoPlayerImplementor mp4Player = new MP4VideoPlayer();VideoPlayer windowsFLVPlayer = new WindowsVideoPlayer(flvPlayer);VideoPlayer linuxMP4Player = new LinuxVideoPlayer(mp4Player);windowsFLVPlayer.play();  // 在Windows系统上播放FLV视频linuxMP4Player.play();    // 在Linux系统上播放MP4视频}
}

在这个示例中,我们首先定义了视频播放器的实现接口(VideoPlayerImplementor),然后创建了具体实现类,表示不同视频格式的播放器。接着,我们定义了视频播放器的抽象类(VideoPlayer)和扩展抽象类,表示不同操作系统上的播放器。最后,通过客户端代码,我们可以选择不同的视频格式和操作系统,实现了桥接模式的应用。这使我们能够轻松扩展支持更多格式和操作系统的播放器,而不会修改现有代码。

6 典型应用场景

桥接模式在以下情况下非常有用:

当你需要避免在抽象和具体实现之间存在静态绑定关系时。
当一个类存在多个独立变化的维度,且需要独立扩展时,可以使用桥接模式来管理这些维度。
当你希望一个抽象部分的变化不会影响到客户端代码时,可以使用桥接模式。
典型应用包括不同操作系统上的图形用户界面库、不同数据库连接的数据库访问库等。

7 优缺点

优点:
解耦性:桥接模式将抽象和实现分离,降低了它们之间的耦合度。
可扩展性:可以方便地添加新的抽象和具体实现,而不会影响到已有的代码。
可维护性:由于分离了抽象和具体实现,代码更容易理解和维护。
符合开闭原则:可以在不修改现有代码的情况下扩展系统功能。
缺点:
增加复杂性:引入了额外的抽象层次,可能会增加代码的复杂性。
增加开发时间:相对于直接使用继承,桥接模式可能需要更多的开发时间

8 类似模式

桥接模式和类似模式中,有两种最常见的模式是适配器模式和装饰者模式。它们都属于结构型设计模式,并且在某些情况下可以与桥接模式有一定的联系。
在这里插入图片描述

  • 适配器模式(Adapter Pattern)

联系:适配器模式通常用于使一个类的接口与另一个类的接口兼容,它的主要目的是使接口不兼容的类能够协同工作。在某种程度上,适配器模式也可以解决桥接模式中的问题,因为它们都涉及将不同的接口协同工作。

区别:适配器模式的主要焦点是在不同接口之间进行适配,通常是通过包装一个类来实现。而桥接模式的主要焦点是将抽象部分与实现部分分离,允许它们独立变化。桥接模式更加注重组合而不是适配。

  • 装饰者模式(Decorator Pattern)

联系:装饰者模式和桥接模式都涉及到在运行时组合对象,而不是静态继承。它们都允许你在不修改核心类的情况下增加功能。

区别:装饰者模式主要用于动态地添加额外的职责或行为,而不改变对象的接口。它通常以一种递归的方式构建,每个装饰者都有一个基本组件的引用。相反,桥接模式的主要目标是将抽象部分和实现部分分离,以便它们可以独立变化,而不影响客户端。

虽然这些模式有一些相似之处,但它们的关注点和目标略有不同。桥接模式主要关注将抽象和实现分离,允许它们独立变化,通常涉及多个维度的变化。适配器模式主要关注接口的适配,以使不兼容的类能够协同工作。装饰者模式主要用于动态地增加对象的功能。在实际应用中,选择合适的模式取决于具体问题的需求。

9 小结

桥接模式是一种强大的设计模式,它可以将抽象和实现分离,使得系统更加灵活、可扩展和易于维护。通过示例、结构、实现步骤、代码实现、典型应用场景、优缺点以及类似模式的介绍,我们希望您现在对桥接模式有了更深入的理解,并能够在实际项目中合理应用它以解决复杂性和提高代码质量。桥接模式适用于需要处理多个独立变化维度的情况,以及需要保持灵活性和可扩展性的项目中。

在使用桥接模式时,确保仔细设计抽象和实现部分的接口,以便将它们正确连接起来。同时,要注意避免过度使用桥接模式,因为它可能增加代码的复杂性,只有在确实需要将抽象和实现分离时才应该采用这种模式。

最后,深入理解设计模式并将其应用到实际项目中需要时间和实践。桥接模式是设计模式中的一个重要工具,它可以帮助你构建更加灵活和可维护的软件系统。希望这篇博客能够帮助你更好地理解和应用桥接模式。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

液氮超低温保存法的原理

细菌保存是有效保存活体微生物群体,使细菌不死、不衰、不变,便于研究和应用。保存细菌的方法有很多。保存原理是利用干燥、低温、隔离空气的方法,降低微生物菌株的代谢速度,使菌株的生命活动处于半永久性休眠状态,从而…

【C++】手撕string(string的模拟实现)

手撕string目录: 一、 Member functions 1.1 constructor 1.2 Copy constructor(代码重构:传统写法和现代写法) 1.3 operator(代码重构:现代写法超级牛逼) 1.4 destructor 二、Other mem…

多旋翼无人机组合导航系统-多源信息融合算法(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

动手吧,vue数字动画

数字动画&#xff0c;有数字的地方都能用上&#xff0c;拿去吧&#xff01; 效果&#xff1a; 1、template部分 <template><div class"v-count-up">{{ dispVlaue }}</div> </template> 2、js部分 export default {data() {return {timer…

【LeetCode热题100】--54.螺旋矩阵

54.螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 按层遍历 可以将矩阵看成若干层&#xff0c;首先输出最外层的元素&#xff0c;其次输出次外层的元素&#xff0c;直到输出最内层的元素。 对于每层&…

【二叉树】——链式结构(快速掌握递归与刷题技巧)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

《学术小白学习之路12》进阶-基于Python实现中文文本的DTM主题动态模型构建

《学术小白学习之路》基于Python实现中文文本的DTM主题动态模型构建 一、数据选择二、数据预处理三、输入数据ID映射词典构建四、文档加载成构造语料库五、DTM模型构建与结果分析六、结果进行保存七、保存模型一、数据选择 所选取的数据集是论文摘要,作为实验数据集,共计12条…

基于微信小程序的校园代送跑腿系统(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

[C++网络协议] 优于select的epoll

1.epoll函数为什么优于select函数 select函数的缺点&#xff1a; 调用select函数后&#xff0c;要针对所有文件描述符进行循环处理。每次调用select函数&#xff0c;都需要向该函数传递监视对象信息。 对于缺点2&#xff0c;是提高性能的最大障碍。因为&#xff0c;套接字是…

python+requests+pytest+allure自动化框架

1.核心库 requests request请求 openpyxl excel文件操作 loggin 日志 smtplib 发送邮件 configparser unittest.mock mock服务 2.目录结构 base utils testDatas conf testCases testReport logs 其他 2.1base base_path.py 存放绝对路径,dos命令或Jenkins执行…

C++,异常、转换函数、智能指针

目录 一、异常 1 C 异常机制&#xff1a; 2 使用try catch进行异常处理. 3、c 已经内置标准异常类&#xff0c;专业用于抛出的语法中 4 自定义异常&#xff1a; 5 函数只抛出&#xff0c;不处理。让上层函数处理&#xff0c;并且上层函数还可以不处理&#xff0c;让上上层…

Spring 学习(六)代理模式

10. 代理模式 案例 10.1 静态代理 角色分析 抽象角色&#xff1a;一般使用接口或者抽象类实现。真实角色&#xff1a;被代理的角色。代理角色&#xff1a;代理真实角色&#xff0c;含附属操作。客户&#xff1a;访问代理对象的角色。 租房案例 定义租赁接口 /*** TODO* 租房*…

MySQL 基础

本系列文章为【狂神说 Java 】视频的课堂笔记&#xff0c;若有需要可配套视频学习。 1. 简介 数据库&#xff08;DB&#xff0c;Database&#xff09;是安装在操作系统上的存储数据的软件。 关系型数据库&#xff08;RDB&#xff09;以行列形式存储数据。 非关系型数据库&am…

竞赛选题 基于视觉的身份证识别系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的身份证识别系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-sen…

第二届全国高校计算机技能竞赛——Java赛道

第二届全国高校计算机技能竞赛——Java赛道 小赛跳高 签到题 import java.util.*; public class Main{public static void main(String []args) {Scanner sc new Scanner(System.in);double n sc.nextDouble();for(int i 0; i < 4; i) {n n * 0.9;}System.out.printf(&…

JavaScript系列从入门到精通系列第四篇:JavaScript基本语法(二)

文章目录 前言 一&#xff1a;Number类型 1&#xff1a;字符串与Number类型 2&#xff1a;检查数据类型 3&#xff1a;Number最大值 4&#xff1a;Number四则运算精确性 二&#xff1a;布尔值 1&#xff1a;布尔值数量 2&#xff1a;布尔值类型查看 三&#xff1a;N…

基于微信小程序的电影院订票系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言运行环境说明用户微信小程序端的主要功能有&#xff1a;管理员的主要功能有&#xff1a;具体实现截图详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考论文参考源码获取 前言 &#x1f497;博主介绍&…

python -文件相关操作

文章目录 前言python -文件相关操作1. 读取文件1.1. 读取整个文件内容1.2. 读取文件的一行内容1.3. 将文件的内容按行存储到一个列表中 2. 写入文件3. 删除文件4. 追加文件5. 遍历文件5.1. 使用 os 模块 遍历文件5.2. # 使用 glob 模块 遍历文件5.3. 使用os.listdir() 函数遍历…

LeetCode 接雨水 双指针

原题链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题面&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a…

TS编译选项——不允许使用隐式any类型、不明确类型的this、严格检查空值、编译后文件自动设置严格模式

一、不允许使用隐式any类型 在tsconfig.js文件中配置noImplicitAny属性 {"compilerOptions": {// 不允许使用隐式any类型"noImplicitAny": true} } 开启后即可禁止使用隐式的any类型 注意&#xff1a;显式的any类型并不会被禁止 二、不允许使用不明确类…