设计模式之桥接模式:抽象与实现之间的分离艺术

桥接模式概述与角色组成
想象一下你家里的电视遥控器,无论是索尼还是三星的电视机,遥控器的按键功能都差不多:有开关按钮、音量调节、频道切换等。遥控器本身的功能(抽象)和具体品牌电视的实现(实现)是分离的,这就是桥接模式的一个生动写照。
桥接模式的核心思想是将抽象部分与实现部分分离,让它们都可以独立变化。这就好比建造一座桥,把两个独立的部分连接起来。在我们的电视机例子中,遥控器就是连接用户操作和电视机的"桥梁"。

如上图所示,桥接模式由四个核心角色组成:
- 抽象类(Abstraction):定义抽象类的接口,它包含一个对实现类接口的引用。就像遥控器的抽象类,定义了基本的控制功能,并持有对具体电视机的引用。
- 扩展抽象类(RefinedAbstraction):扩展抽象类,加入更多的功能特性。比如在基础遥控器的基础上,添加了更多高级功能的智能遥控器。
- 实现类接口(Implementor):定义实现类的接口,供抽象类调用。就像所有品牌电视机都应该遵循的标准接口,定义了开关机、调节音量等基本功能。
- 具体实现类(ConcreteImplementor):实现实现类接口的具体类。例如索尼电视机、三星电视机等具体品牌的电视机实现。
这种设计的妙处在于:如果我们要添加一种新的遥控器类型(比如带语音控制的遥控器),只需要扩展抽象类;如果要支持一个新品牌的电视机,只需要添加具体实现类。两个维度的变化互不影响,大大提高了系统的灵活性和可扩展性。
桥接模式案例实现
让我们通过遥控器控制电视机的完整示例,来深入理解桥接模式的实现。

首先,我们定义电视机的接口:
public interface TV {void on();void off();void tuneChannel(int channel);
}
然后实现具体品牌的电视机:
public class SonyTV implements TV {@Overridepublic void on() {System.out.println("索尼电视机启动");}@Overridepublic void off() {System.out.println("索尼电视机关闭");}@Overridepublic void tuneChannel(int channel) {System.out.println("索尼电视切换到" + channel + "频道");}
}public class SamsungTV implements TV {@Overridepublic void on() {System.out.println("三星电视机启动");}@Overridepublic void off() {System.out.println("三星电视机关闭");}@Overridepublic void tuneChannel(int channel) {System.out.println("三星电视切换到" + channel + "频道");}
}
接下来定义遥控器的抽象类:
public abstract class RemoteControl {protected TV tv;public RemoteControl(TV tv) {this.tv = tv;}public abstract void turnOn();public abstract void turnOff();
}
实现具体的遥控器类:
public class BasicRemote extends RemoteControl {public BasicRemote(TV tv) {super(tv);}@Overridepublic void turnOn() {System.out.println("基础遥控器:打开电视");tv.on();}@Overridepublic void turnOff() {System.out.println("基础遥控器:关闭电视");tv.off();}
}public class AdvancedRemote extends RemoteControl {public AdvancedRemote(TV tv) {super(tv);}@Overridepublic void turnOn() {System.out.println("高级遥控器:打开电视");tv.on();}@Overridepublic void turnOff() {System.out.println("高级遥控器:关闭电视");tv.off();}// 高级遥控器特有的功能public void setChannel(int channel) {System.out.println("高级遥控器:切换频道");tv.tuneChannel(channel);}
}
下面通过一个具体的客户端代码来演示如何使用这个遥控器-电视机系统:
public class Client {public static void main(String[] args) {// 创建不同品牌的电视TV sonyTV = new SonyTV();TV samsungTV = new SamsungTV();// 创建不同类型的遥控器RemoteControl basicRemote = new BasicRemote(sonyTV);AdvancedRemote advancedRemote = new AdvancedRemote(samsungTV);// 使用基础遥控器操作索尼电视System.out.println("使用基础遥控器操作索尼电视:");basicRemote.turnOn();basicRemote.turnOff();System.out.println("使用高级遥控器操作三星电视:");advancedRemote.turnOn();advancedRemote.setChannel(5);advancedRemote.turnOff();}
}
运行结果如下:

让我们通过下面的时序图来详细说明对象之间的交互过程:

从时序图中我们可以清晰地看到,当客户端调用遥控器的turnOn()方法时,遥控器会将请求转发给具体的电视机实现类。这种方式让遥控器和电视机之间形成了一个优雅的"桥接",它们可以独立变化而互不影响。
桥接模式的优缺点
优点
- 很好地实现了抽象和实现的分离。就像我们的例子中,遥控器的功能和电视机的实现是完全分离的,这让我们能够独立地扩展任意一边而不会影响另一边。你可以添加一个带有语音控制功能的遥控器,而不需要修改任何电视机的代码。
- 提高了系统的可扩展性。当系统需要添加新的实现时,只需要增加新的类,而不需要修改现有的代码。比如要支持新品牌的电视机,只需要实现TV接口即可,不需要修改任何遥控器的代码。
- 对客户端来说很友好。客户端代码只需要知道抽象部分的接口,而不需要了解具体实现的细节。在我们的例子中,使用遥控器的人只需要知道按键的功能,而不需要关心不同品牌电视机的具体实现差异。
缺点
- 增加了系统的复杂度。为了实现抽象和实现的分离,我们需要额外的接口和类。对于简单的系统来说,使用桥接模式可能会显得有点过度设计。
- 要求正确识别系统中的两个独立变化的维度。如果对系统的理解不够深入,可能会导致对抽象和实现的划分不当,反而增加系统的维护难度。
桥接模式的适用场景
- 当一个系统需要在抽象和实现之间具有灵活性时。例如,我们的遥控器和电视机的例子,两者之间的组合是动态的,任何遥控器都可以操控任何品牌的电视机。
- 当系统中有两个或多个独立变化的维度时。比如除了遥控器和电视机的例子,类似的场景还有:形状和颜色(可以有不同形状和不同颜色的组合)、平台和视图(可以在不同平台上实现不同的视图)等。
- 当需要跨平台或跨数据库时。桥接模式可以让具体的平台实现和业务逻辑分离,使得系统可以轻松地支持新的平台。
- 当需要在运行时切换不同的实现时。由于抽象和实现是分离的,我们可以在运行时动态地改变实现,而不会影响到使用抽象接口的代码。
总结
桥接模式通过将抽象部分与实现部分分离,实现了两个维度上的独立扩展。就像遥控器和电视机的例子展示的那样,它让我们能够在不修改现有代码的情况下,轻松地添加新的遥控器类型或支持新品牌的电视机。
在实际应用中,使用桥接模式时需要注意以下几点:首先,要准确识别系统中独立变化的维度;其次,要合理划分抽象和实现的界限;最后,要避免过度设计,对于简单的系统,使用过于复杂的模式反而会增加开发和维护的成本。
桥接模式的精髓在于"分离抽象与实现",这种分离让系统更加灵活,更容易扩展和维护。当你遇到类似的场景时,不妨考虑使用桥接模式来优化你的设计。

相关文章:
设计模式之桥接模式:抽象与实现之间的分离艺术
~犬📰余~ “我欲贱而贵,愚而智,贫而富,可乎? 曰:其唯学乎” 桥接模式概述与角色组成 想象一下你家里的电视遥控器,无论是索尼还是三星的电视机,遥控器的按键功能都差不多࿱…...
网络隧道与代理
文章目录 网络隧道网络代理参考 网络隧道 使用隧道的原因是在不兼容的网络上传输数据,或在不安全网络上提供一个安全路径。网络隧道的一个典型特征就是封装报文和对报文加密。如下是两个典型的案例:IPv4到IPv6的迁移、VPN。 图3.1 IPv4到IPv6的迁移 图…...
游戏关卡分析:荒野大镖客2雪山终战
1、相关剧情 主角约翰一家在农场过着悠闲的日子,突然平静被打破, 女枪手来报信,在某小镇找到了迈卡的消息。 于是激发了约翰的满腔怒气,不顾妻子的反对,坚决要出战, 要彻底歼灭迈卡,为亚瑟…...
Java 中的 LocalDateTime、DateTime 和 Date 的区别解析
目录 前言 一、LocalDateTime:新的 Java 8 日期时间 API 1.1 LocalDateTime 简介 1.2 设计理念 1.3 适用场景 1.4 示例代码 二、DateTime:没有明确标准的类 2.1 DateTime 的模糊性 2.2 适用场景 三、Date:老旧的日期时间类 3.1 Da…...
MATLAB引用矩阵元素的几种方法
引用矩阵元素可以通过索引,也可以通过逻辑值 索引 通过引用元素在矩阵中的位置来提取元素,例如: - 逻辑值 通过某种逻辑运算来使得要提取的值变为逻辑 1 1 1,用 A ( ) A() A()提取即可, A A A为原矩阵的名称。 例如&…...
Linux、File System、Linux基本常用命令
一、File System 文件系统 Linux文件系统是操作系统用来组织、管理和存储问价及目录结构的方式。它不仅定义了如何将数据保存到磁盘上,还规定了用户如何与这些数据进行交互。 1、层次结构 根目录(/):所有文件和目录都从根目录开始…...
大数据治理:开启数据价值挖掘之旅
在当今数字化时代,数据呈爆炸式增长,大数据已经渗透到各个行业和领域,成为企业竞争和创新的关键驱动力。而大数据治理作为有效管理和利用大数据资源的核心手段,在教学领域也具有至关重要的地位。 一、大数据治理的内涵与重要性 大…...
Linux排查cpu运行负载过高
方式1:top 先输入top再输入1,查看 %CPU 列,找出占用 CPU 最多的进程 作用:切换显示每个逻辑 CPU 的使用情况。效果: 如果系统有多个 CPU 核心或超线程逻辑处理器,按下 1 会使得 top 分别显示每个逻辑 CPU…...
Cobalt Strike 4.8 用户指南-第十四节 Aggressor 脚本
14.1、什么是Aggressor脚本 Aggressor Script 是Cobalt Strike 3.0版及更高版本中内置的脚本语言。Aggressor 脚本允许你修改和扩展 Cobalt Strike 客户端。 历史 Aggressor Script 是 Armitage 中开源脚本引擎Cortana的精神继承者。Cortana 是通过与 DARPA 的网络快速跟踪计…...
C++并发与多线程(高级函数async)
async 在 C 中,async 关键字用于实现异步编程,它允许你定义异步操作,这些操作可以在后台执行,而不会阻塞当前线程。这是 C11 引入的特性,与 std::async 函数和 std::future 类一起使用。与thread函数模板的区别在于as…...
安卓课设版算法计算器
安卓课设版算法计算器(HNUST) 前言: 如果只想看函数使用说明请跳转到“四、使用函数介绍” 该版本为课设版,富含多个界面,是前版的plus版本,进行了更多的复杂化操作,故因此会觉得对于计算器有点…...
X-Forwarded-For注入漏洞
0x00环境介绍 靶机http://219.153.49.228:48033,通过注入完成找到网站的key。 1|00x01复现过程 1.访问网站使用admin/admin登入,用burpsuite截包寻找注入点 >>截到的包,正常放包回显内容 >>加X-forwarded-for:1.1.1.1回显IP数据改变&…...
Linux - MySQL迁移至一主一从
Linux - MySQL迁移至一主一从 迁移准备安装MySQL ibd文件迁移原服务器操作目标服务器操作 一主一从增量同步异常解决结尾 首先部分单独安装MySQL,请参考Linux - MySQL安装,迁移数据量比较大约400G左右且网络不通故使用文件迁移,需开启一段时间…...
《变形金刚:赛博坦的陨落》游戏启动难题:‘buddha.dll’缺失的七大修复策略
《变形金刚:赛博坦的陨落》游戏启动时提示buddha.dll缺失:原因与解决方案 作为一名软件开发从业者,我在日常工作中经常遇到电脑游戏运行时出现的各种问题,如文件丢失、文件损坏和系统报错等。今天,我们就来探讨一下《…...
51c嵌入式~单片机~合集2
我自己的原文哦~ https://blog.51cto.com/whaosoft/12362395 一、不同的电平信号的MCU怎么通信? 下面这个“电平转换”电路,理解后令人心情愉快。电路设计其实也可以很有趣。 先说一说这个电路的用途:当两个MCU在不同的工作电压下工作&a…...
java Resource 记录
Java 注解 Resource 是一个标准的 Java 注解,用于注入资源。它可以用于注入任何资源,如文件、数据库连接、用户定义的资源等。它可以通过名称或类型进行注入。 当你想要注入一个bean到你的类中时,你可以使用Resource注解。 解决方案1&#…...
Avalonia 开发环境准备
总目录 前言 介绍如何搭建 Avalonia 开发环境。 一、在线开发环境搭建 请先安装您选择的受支持的IDE。Avalonia 支持 Visual Studio、Rider 和 Visual Studio Code。 详见:https://docs.avaloniaui.net/zh-Hans/docs/get-started/install 1. 使用 Visual Studio 20…...
C# 中 Console.WriteLine($“{DateTime.Now.Date}“); win 和 docker容器输出不同
Console.WriteLine($"{DateTime.Now.Date}"); //windowns输出:2024/12/10 0:00:00 //docker容器输出:12/10/2024 00:00:00 这是由于 不同的文化区域(CultureInfo)设置 导致的时间格式差异。在 Windows 系统…...
回型矩阵:JAVA
解题思路: 通过定义四条边界;top,left,right,bottom,来循环,当top>bottom&&left>right的时候循环终止 循环结束的条件: 链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述…...
从零开始学习 sg200x 多核开发之 sophpi 编译生成 fip.bin 流程梳理
本文主要介绍 sophpi 编译生成 fip.bin 流程。 1、编译前准备 sophpi 的基本编译流程如下: $ source build/cvisetup.sh $ defconfig sg2002_wevb_riscv64_sd $ clean_all $ build_all $ pack_burn_image注: 需要在 bash 下运行clean_all 非必要可以不…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...
当下AI智能硬件方案浅谈
背景: 现在大模型出来以后,打破了常规的机械式的对话,人机对话变得更聪明一点。 对话用到的技术主要是实时音视频,简称为RTC。下游硬件厂商一般都不会去自己开发音视频技术,开发自己的大模型。商用方案多见为字节、百…...
