设计模式(结构型)-桥接模式

news2025/4/18 20:36:21

目录

摘要

定义

类图

角色

具体实现

优缺点

优点

缺点

使用场景

使用案例

JDBC 和桥接模式

总结


摘要

        在软件开发领域,随着系统规模和复杂性的不断攀升,如何设计出具有良好扩展性、灵活性以及可维护性的软件架构成为关键挑战。桥接模式作为一种重要的结构型设计模式,为解决这些问题提供了有效的方案。它通过巧妙的设计,将抽象部分与实现部分进行分离,使二者能够独立发展变化,极大地提升了软件系统应对变化的能力。

定义

        将抽象部分与它的实现部分分离,使它们都可以独立地变化。在许多传统设计中,抽象与实现紧密耦合,一旦其中一方发生改变,往往会对另一方产生较大影响,这无疑增加了系统的维护成本和复杂性。桥接模式则打破了这种束缚,通过聚合关系代替继承关系,实现了抽象化和实现化部分的解耦。​

        例如,在一个图形绘制系统中,假设我们有不同类型的图形(如圆形、矩形等),同时需要在不同的平台(如 Windows、Mac 等)上进行绘制。若采用传统的继承方式,每一种图形类型都需要为每个平台创建一个子类,这样会导致类的数量呈指数级增长,代码的维护和扩展变得极为困难。而桥接模式可以将图形的抽象(如 Shape 类)与具体的绘制实现(如 WindowsDrawingAPI、MacDrawingAPI 等实现类)分离,通过聚合关系将它们关联起来,使得图形类型和绘制平台能够独立发展,大大简化了系统的设计。

类图

角色

  • Abstraction(抽象类):处于整个结构的上层,用于定义抽象的接口。它一般是抽象类而非接口,其中定义了一个 Implementor(实现类接口)类型的对象并维护该对象,通过这种方式与 Implementor 建立关联关系。抽象类中声明的方法往往依赖于 Implementor 中定义的操作来实现具体功能。​

  • RefinedAbstraction(提炼抽象类):对 Abstraction 定义的接口进行扩充。通常情况下,它不再是抽象类而是具体类,实现了在 Abstraction 中声明的抽象业务方法。在其实现过程中,会调用在 Implementor 中定义的业务方法,从而将抽象与实现进行结合。​

  • Implementor(实现类接口):该接口定义了实现类的基本操作规范。需要注意的是,它的接口设计不一定要与 Abstraction 的接口完全一致,事实上二者可能差异较大。Implementor 接口主要聚焦于提供一些基础的、底层的操作,这些操作的具体实现由其子类负责。通过这种抽象接口的定义,为不同的具体实现提供了统一的规范。​

  • ConcreteImplementor(具体实现类):具体实现 Implementor 接口的类,针对不同的业务需求和场景,在各个 ConcreteImplementor 中提供基本操作的不同实现。在程序运行过程中,ConcreteImplementor 对象会替换其父类对象,为抽象类提供具体的业务操作方法,实现实际的功能。

具体实现

  • Abstraction(抽象类):作为抽象层的代表,它为整个系统提供了一个高层次的抽象接口。以图形绘制系统为例,抽象类 Shape 可以定义一些通用的图形操作方法,如绘制(draw)、缩放(resize)等,但并不涉及具体的绘制逻辑。它持有一个实现类接口 IDrawingAPI 类型的对象,通过该对象来调用具体的绘制实现。

public abstract class Shape {​
    protected IDrawingAPI drawingAPI;​
    public Shape(IDrawingAPI drawingAPI) {​
        this.drawingAPI = drawingAPI;​
    }​
    public abstract void draw();​
    public abstract void resize(double factor);​
}
  • RefinedAbstraction(提炼抽象类):以 Circle 类为例,它继承自 Shape 抽象类,是提炼抽象类的具体体现。在 Circle 类中,实现了 Shape 类中定义的 draw 和 resize 方法,并借助 drawingAPI 对象调用具体的绘制实现。

public class Circle extends Shape {​
    private double x, y, radius;​
    public Circle(double x, double y, double radius, IDrawingAPI drawingAPI) {​
        super(drawingAPI);​
        this.x = x;​
        this.y = y;​
        this.radius = radius;​
    }​
    @Override​
    public void draw() {​
        drawingAPI.drawCircle(x, y, radius);​
    }​
    @Override​
    public void resize(double factor) {​
        radius *= factor;​
    }​
}
  • Implementor(实现类接口):定义了具体实现类需要遵循的接口规范。在图形绘制系统中,IDrawingAPI 接口定义了绘制圆形、矩形等图形的方法。

public interface IDrawingAPI {​
    void drawCircle(double x, double y, double radius);​
    void drawRectangle(double x1, double y1, double x2, double y2);​
}
  • ConcreteImplementor(具体实现类):如 WindowsAPI 和 MacAPI 类,分别实现了 IDrawingAPI 接口,提供了在 Windows 和 Mac 平台上的具体绘制实现。

public class WindowsAPI implements IDrawingAPI {​
    @Override​
    public void drawCircle(double x, double y, double radius) {​
        System.out.println("在Windows平台绘制圆形,圆心:(" + x + ", " + y + "),半径:" + radius);​
    }​
    @Override​
    public void drawRectangle(double x1, double y1, double x2, double y2) {​
        System.out.println("在Windows平台绘制矩形,左上角:(" + x1 + ", " + y1 + "),右下角:(" + x2 + ", " + y2 + ")");​
    }​
}​
public class MacAPI implements IDrawingAPI {​
    @Override​
    public void drawCircle(double x, double y, double radius) {​
        System.out.println("在Mac平台绘制圆形,圆心:(" + x + ", " + y + "),半径:" + radius);​
    }​
    @Override​
    public void drawRectangle(double x1, double y1, double x2, double y2) {​
        System.out.println("在Mac平台绘制矩形,左上角:(" + x1 + ", " + y1 + "),右下角:(" + x2 + ", " + y2 + ")");​
    }​
}

优缺点

优点

  • 实现抽象和实现的分离:这是桥接模式的核心优势。通过将抽象部分与实现部分解耦,使得它们能够独立地进行演化。例如,在图形绘制系统中,图形类型的扩展(如新增三角形、菱形等图形)不会影响到绘制平台的实现,反之,绘制平台的更新(如支持新的操作系统)也不会对图形类型造成影响,大大提高了系统的灵活性和可维护性。​

  • 提高系统的可扩充性:在桥接模式下,两个变化维度(抽象和实现)中的任意一个进行拓展,都无需对原有系统进行大规模修改。以消息发送系统为例,若要新增一种消息类型(如推送消息),只需在抽象部分添加相应的类,并在实现部分关联已有的消息发送方式(如邮件、短信等);若要新增一种消息发送方式(如即时通讯工具),也只需在实现部分添加具体实现类,然后在需要使用的抽象类中进行关联即可,符合开闭原则。​

  • 避免多层继承的弊端:多层继承方案容易违背类的单一职责原则,导致代码复用性差,并且类的数量会随着继承层次的增加而迅速膨胀,使得系统变得复杂难以维护。桥接模式采用聚合关系替代继承关系,有效避免了这些问题,使得系统结构更加简洁清晰。

缺点

  • 增加系统的理解与设计难度:由于桥接模式中的聚合关联关系建立在抽象层,这要求开发者在设计和编程时,需要从更高的抽象层次去思考和规划,对开发者的抽象思维能力和设计经验有较高要求。初学者可能较难理解和掌握这种设计方式,增加了学习和上手的难度。​

  • 使用范围具有一定的局限性:桥接模式的应用依赖于正确识别出系统中两个独立变化的维度。然而,在一些复杂系统中,准确判断和分离这两个维度并非易事。如果对系统的分析不准确,强行使用桥接模式,可能不仅无法发挥其优势,反而会使系统变得更加复杂混乱,因此其使用场景受到一定限制。

使用场景

  • 一个类存在两个独立变化的维度,且这两个维度都需要进行拓展:例如在电商系统中,商品有不同的类别(如电子产品、服装、食品等),同时有不同的促销策略(如打折、满减、赠品等)。类别和促销策略这两个维度相互独立且都可能不断扩展,使用桥接模式可以将商品类别抽象与促销策略实现进行分离,方便系统根据业务发展进行功能扩展。​

  • 如果一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系:以跨平台的游戏开发为例,游戏中的角色具有各种行为(如移动、攻击、防御等抽象行为),而这些行为在不同的游戏平台(如 PC、手机、主机等)上有不同的实现方式。通过桥接模式,可以将角色行为的抽象与平台相关的实现解耦,使游戏在不同平台上的移植和扩展更加容易,提高了系统的灵活性。​

  • 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统:如在图形编辑软件中,图形元素有多种类型(矩形、圆形、多边形等),并且需要支持不同的显示模式(普通模式、高清模式、3D 模式等)。若采用继承方式,会产生大量的子类(每种图形类型对应每种显示模式都需要一个子类)。使用桥接模式,将图形类型抽象与显示模式实现分离,可以有效避免类的数量爆炸,简化系统设计。

使用案例

JDBC 和桥接模式

        JDBC(Java Database Connectivity)是 Java 语言中用于连接和操作数据库的标准 API,它很好地体现了桥接模式的应用。在 JDBC 中,抽象部分是 Java.sql 包中定义的一系列接口,如 Connection、Statement、ResultSet 等,这些接口定义了与数据库交互的抽象操作,如建立连接、执行 SQL 语句、获取查询结果等。而实现部分则是各个数据库厂商提供的数据库驱动,如 MySQL 的驱动、Oracle 的驱动等。不同的数据库驱动实现了 Java.sql 包中的接口,提供了针对各自数据库的具体操作实现。​

        通过这种方式,Java 程序在使用 JDBC 操作数据库时,无需关心具体使用的是哪种数据库以及其底层实现细节,只需要通过抽象接口进行操作。当需要更换数据库时,只需要更换对应的数据库驱动(实现部分),而 Java 程序中使用 JDBC 接口的代码(抽象部分)无需修改,极大地提高了代码的可移植性和可维护性,充分发挥了桥接模式将抽象与实现分离的优势。​

总结

        桥接模式作为一种强大的结构型设计模式,通过独特的设计理念和结构,有效地解决了软件系统中抽象与实现耦合的问题,为构建灵活、可扩展的软件架构提供了有力的支持。虽然它存在一定的应用门槛和局限性,但在合适的场景下应用,能够显著提升软件系统的质量和开发效率,是开发者在软件设计过程中不可或缺的重要工具。

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

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

相关文章

【MySQL】MySQL数据库 —— 简单认识

目录 1. 数据库的介绍 1.1 什么是数据库 1.2 数据库和数据结构之间关系 2. 数据库分类 2.1 关系型数据库(RDBMS) 2.2 非关系型数据库 2.3 区别 一些行内名词简单解释: 3. 关于mysql 主要学什么 4. MySQL中重要的概念 4.1 概念 4…

RNN - 语言模型

语言模型 给定文本序列 x 1 , … , x T x_1, \ldots, x_T x1​,…,xT​,语言模型的目标是估计联合概率 p ( x 1 , … , x T ) p(x_1, \ldots, x_T) p(x1​,…,xT​)它的应用包括 做预训练模型(eg BERT,GPT-3)生成本文&#xff…

过拟合、归一化、正则化、鞍点

过拟合 过拟合的本质原因往往是因为模型具备方差很大的权重参数。 定义一个有4个特征的输入,特征向量为,定义一个模型,其只有4个参数,表示为。当模型过拟合时,这四个权重参数的方差会很大,可以假设为。当经过这个模型后…

【python画图】:从入门到精通绘制完美柱状图

目录 Python数据可视化:从入门到精通绘制完美柱状图一、基础篇:快速绘制柱状图1.1 使用Matplotlib基础绘制1.2 使用Pandas快速绘图 二、进阶篇:专业级柱状图定制2.1 多系列柱状图2.2 堆叠柱状图2.3 水平柱状图 三、专业参数速查表Matplotlib …

基础知识:离线安装docker、docker compose

(1)离线安装docker 确认版本:Ubuntu 18.04 LTS - bionic 确认架构:X86_64 lsb_release -a uname -a 官方指南:https://docs.docker.com/engine/install/ 选择Ubuntu,发现页面上最低是Ubuntu20.04, 不要紧

畅游Diffusion数字人(27):解读字节跳动提出主题定制视频生成技术Phantom

畅游Diffusion数字人(0):专栏文章导航 前言:主题定制视频生成,特别是zero-shot主题定制视频生成,一直是当前领域的一个难点,之前的方法效果很差。字节跳动提出了一个技术主题定制视频生成技术Phantom,效果相比于之前的技术进步非常显著。这篇博客详细解读一下这一工作。 …

《Adaptive Layer-skipping in Pre-trained LLMs》- 论文笔记

作者:Xuan Luo, Weizhi Wang, Xifeng Yan Department of Computer Science, UC Santa Barbara xuan_luoucsb.edu, weizhiwangucsb.edu, xyancs.ucsb.edu 1. 引言与动机 1.1 背景 LLM 的成功与挑战: 大型语言模型 (LLMs) 在翻译、代码生成、推理等任务上取得巨大成…

微信小程序实现table样式,自带合并行合并列

微信小程序在代码编写过程好像不支持原生table的使用&#xff0c;在开发过程中偶尔又得需要拿table来展示。 1.table效果展示 1.wxml <view class"table-container"><view class"table"><view class"table-row"><view cla…

电脑的品牌和配置

我的笔记本是2020年买的&#xff0c;之前的订单找不到了&#xff0c;就知道是联想&#xff0c;不清楚具体的配置。 本文来源&#xff1a;腾讯元宝 检查系统信息&#xff08;Windows&#xff09; 这通常是 ​​联想&#xff08;Lenovo&#xff09;​​ 的型号代码。 81XV 是联想…

Redis面试——常用命令

一、String &#xff08;1&#xff09;设置值相关命令 1.1.1 SET 功能&#xff1a;设置一个键值对&#xff0c;如果键已存在则覆盖旧值语法&#xff1a; SET key value [EX seconds] [PX milliseconds] [NX|XX]EX seconds&#xff1a;设置键的过期时间为 seconds 秒 PX milli…

Swin-Transformer-UNet改进:融合Global-Local Spatial Attention (GLSA) 模块详解

目录 1.模块概述 2.swinUNet网络 3. 完整代码 1.模块概述 Global-Local Spatial Attention (GLSA) 是一种先进的注意力机制模块,专为计算机视觉任务设计,能够同时捕捉全局上下文信息和局部细节特征。 该模块通过创新的双分支结构和自适应融合机制,显著提升了特征表示能…

ubuntu 向右拖动窗口后消失了、找不到了

这是目前单显示器的设置&#xff0c;因为实际只有1个显示器&#xff0c;之前的设置如下图所示&#xff0c;有2个显示器&#xff0c;一个主显示器&#xff0c;一个23寸的显示器 ubuntu 22.04 系统 今天在操作窗口时&#xff0c;向右一滑&#xff0c;发现这个窗口再也不显示了、找…

2025最新版微软GraphRAG 2.0.0本地部署教程:基于Ollama快速构建知识图谱

一、前言 微软近期发布了知识图谱工具 GraphRAG 2.0.0&#xff0c;支持基于本地大模型&#xff08;Ollama&#xff09;快速构建知识图谱&#xff0c;显著提升了RAG&#xff08;检索增强生成&#xff09;的效果。本文手把手教你如何从零部署&#xff0c;并附踩坑记录和性能实测…

libevent服务器附带qt界面开发(附带源码)

本章是入门章节&#xff0c;讲解如何实现一个附带界面的服务器&#xff0c;后续会完善与优化 使用qt编译libevent源码演示视频qt的一些知识 1.主要功能有登录界面 2.基于libevent实现的服务器的业务功能 使用qt编译libevent 下载这个&#xff0c;其他版本也可以 主要是github上…

智能体数据分析

数据概览&#xff1a; 展示智能体的累计对话次数、累计对话用户数、对话满意度、累计曝光次数。数据分析&#xff1a; 统计对话分析、流量分析、用户分析、行为分析数据指标&#xff0c;帮助开发者完成精准的全面分析。 ps&#xff1a;数据T1更新&#xff0c;当日12点更新前一天…

STM32(M4)入门: 概述、keil5安装与模板建立(价值 3w + 的嵌入式开发指南)

前言&#xff1a;本教程内容源自信盈达教培资料&#xff0c;价值3w&#xff0c;使用的是信盈达的405开发版&#xff0c;涵盖面很广&#xff0c;流程清晰&#xff0c;学完保证能从新手入门到小高手&#xff0c;软件方面可以无基础学习&#xff0c;硬件学习支持两种模式&#xff…

采用若依vue 快速开发系统功能模块

文章目录 运行若依项目 科室管理科室查询-后端代码实现科室查询-前端代码实现科室名称状态搜索科室删除-后端代码实现科室删除-前端代码实现科室新增-后端代码实现科室新增-前端代码实现科室修改-后端代码实现前端代码实现角色权限实现 运行若依项目 运行redis 创建数据库 修改…

HTML:表格数据展示区

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>人员信息表</title><link rel"styl…

Oracle测试题目及笔记(单选)

所有题目来自于互联网搜索 当 Oracle 服务器启动时&#xff0c;下列哪种文件不是必须的&#xff08;D&#xff09;。 A&#xff0e;数据文件 B&#xff0e;控制文件 C&#xff0e;日志文件 D&#xff0e;归档日志文件 数据文件、日志文件-在数据库的打开阶段使用 控制文件-在数…

Jmeter创建使用变量——能够递增递减的计数器

Jmeter创建使用变量——能够递增递减的计数器 如下图所示&#xff0c;创建一个 取值需限定为0 2 4这三个值内的变量。 Increment&#xff1a;每次迭代后 递增的值&#xff0c;给计数器增加的值 Maximum value&#xff1a;计数器的最大值&#xff0c;如果超过最大值&#xff0…