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

ops/2024/12/24 8:34:31/

在这里插入图片描述

~犬📰余~

“我欲贱而贵,愚而智,贫而富,可乎?
曰:其唯学乎”

桥接模式概述与角色组成

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

  • 抽象类(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接口即可,不需要修改任何遥控器的代码。
  • 对客户端来说很友好。客户端代码只需要知道抽象部分的接口,而不需要了解具体实现的细节。在我们的例子中,使用遥控器的人只需要知道按键的功能,而不需要关心不同品牌电视机的具体实现差异。

缺点

  • 增加了系统的复杂度。为了实现抽象和实现的分离,我们需要额外的接口和类。对于简单的系统来说,使用桥接模式可能会显得有点过度设计。
  • 要求正确识别系统中的两个独立变化的维度。如果对系统的理解不够深入,可能会导致对抽象和实现的划分不当,反而增加系统的维护难度。

桥接模式的适用场景

  • 当一个系统需要在抽象和实现之间具有灵活性时。例如,我们的遥控器和电视机的例子,两者之间的组合是动态的,任何遥控器都可以操控任何品牌的电视机。
  • 当系统中有两个或多个独立变化的维度时。比如除了遥控器和电视机的例子,类似的场景还有:形状和颜色(可以有不同形状和不同颜色的组合)、平台和视图(可以在不同平台上实现不同的视图)等。
  • 当需要跨平台或跨数据库时。桥接模式可以让具体的平台实现和业务逻辑分离,使得系统可以轻松地支持新的平台。
  • 当需要在运行时切换不同的实现时。由于抽象和实现是分离的,我们可以在运行时动态地改变实现,而不会影响到使用抽象接口的代码。

总结

桥接模式通过将抽象部分与实现部分分离,实现了两个维度上的独立扩展。就像遥控器和电视机的例子展示的那样,它让我们能够在不修改现有代码的情况下,轻松地添加新的遥控器类型或支持新品牌的电视机。
在实际应用中,使用桥接模式时需要注意以下几点:首先,要准确识别系统中独立变化的维度;其次,要合理划分抽象和实现的界限;最后,要避免过度设计,对于简单的系统,使用过于复杂的模式反而会增加开发和维护的成本。
桥接模式的精髓在于"分离抽象与实现",这种分离让系统更加灵活,更容易扩展和维护。当你遇到类似的场景时,不妨考虑使用桥接模式来优化你的设计。
在这里插入图片描述

关注犬余,共同进步

技术从此不孤单

http://www.ppmy.cn/ops/144520.html

相关文章

JavaWeb通过Web查询数据库内容:(pfour_webquerymysql)

JavaWeb通过Web查询数据库内容: 数据库: 自行建库建表,主键 id 后端: 新建项目模块选择模块,添加依赖创建配置文件: db.propertiesJava类: query查询 前端: Web添加创建query.html…

基于大语言模型的多代理下一代制造系统能灵活动态管理制造资源的高效调度方法

摘要 论文地址:https://arxiv.org/pdf/2405.16887 随着生产率的提高,客户对多品种、小批量生产的需求也在不断增加,这反过来又对制造系统提出了更高的要求。由于这种需求,当生产任务频繁变化时,传统的制造系统往往无法…

2024.12.23-3 数组指针

定义&#xff1a;一个指针&#xff0c;指向一个数组&#xff0c;真正等于一个二维数组名 运用&#xff1a;int (*p2)[4];表示一个指针&#xff0c;其一个地址含有四个元素。 一次偏移量为16个字节。等同于a[][4]; #include <stdio.h> int main() { int array[3][4]{…

机器学习之假设空间

假设空间是机器学习中的核心概念之一&#xff0c;特别是在监督学习中。它指的是模型在学习过程中所有可能的假设&#xff08;模型函数&#xff09;集合&#xff0c;也就是算法搜索解决方案的空间。 1. 假设空间的定义 假设空间&#xff08;Hypothesis Space&#xff09;可以表…

【WRF教程第3.4期】预处理系统 WPS 详解:以4.5版本为例

预处理系统 WPS 详解&#xff1a;以4.5版本为例 将气象数据写入中间格式&#xff08;Writing Meteorological Data to the Intermediate Format&#xff09;WRF运行所需字段&#xff08;Required Input for Running WRF&#xff09;使用 MPAS 输出作为 WRF 输入&#xff08;Usi…

html 中 表格和表单的关系与区别

在 HTML 中&#xff0c;表格 (<table>) 和表单 (<form>) 是两种常用于展示数据和收集用户输入的元素。它们具有不同的功能和结构。以下是关于这两者的详细介绍&#xff1a; 1. HTML 表格&#xff08;<table>&#xff09; 表格用于展示结构化的数据&#xf…

JDK11下载安装和配置超详细过程

一、下载JDK11资源包 JDK11安装包文件夹资源资源https://download.csdn.net/download/Z0412_J0103/90160803 二、配置环境 2.1 找到文件位置 2.2 打开文件&#xff0c;点击“下一步” ” 2.3 记住文件配置路径&#xff0c;并不要更改&#xff0c;点击下一步 2.4 等待安装完…

裸金属服务器的作用都有哪些?

随着云计算时代的到来&#xff0c;为企业的发展带来了更多的机遇和发展&#xff0c;裸金属服务器则是一种结合了传统物理服务器和虚拟化技术的计算服务&#xff0c;能够为用户提供独享的物理计算资源&#xff0c;本文就将深入探讨一下裸金属服务器的作用与优势。 裸金属服务器有…