10结构型设计模式——桥接模式

news2024/9/22 7:23:50

一、桥接模式

桥接模式(Bridge Pattern)是结构型的设计模式之一。桥接模式基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任。它的主要特点是把抽象(abstraction)与行为实现(implementation)分离开来(解耦合),从而可以保持各部分的独立性以及应对它们的功能扩展。这个模式的关键在于提供一个桥梁,将抽象和具体的实现解耦,从而使得修改和扩展变得更为灵活。

桥接模式的结构图

桥接模式的组成

  1. 抽象类(Abstraction):定义高层次的操作接口,持有一个指向实现类的引用。
  2. 扩展抽象类(RefinedAbstraction):扩展抽象类的功能,但仍然依赖于抽象类定义的接口。
  3. 实现接口(Implementor):定义实现的接口,通常包括一些基本操作,不包括抽象层的操作。
  4. 具体实现类(ConcreteImplementor):实现Implementor(实现接口)的具体操作。

桥接模式的优点

  • 分离抽象与实现:允许在不影响抽象接口的情况下改变实现。
  • 增加灵活性:可以独立地扩展抽象和实现部分。
  • 提高可维护性:通过将功能分离,减少了代码的耦合性,使得维护和扩展更加容易。

二、桥接模式的应用场景 

  1. 需要将抽象和实现分离:当你有一个系统需要同时支持多个维度的变化,比如不同的抽象层次和不同的实现方式,桥接模式能够有效地将这两个维度解耦,使得修改和扩展变得更灵活。

  2. 避免在每个变化点创建大量的子类:如果一个系统中存在多个抽象层次和实现方式,直接继承组合会导致大量的子类产生。桥接模式通过分离抽象和实现,可以避免这种情况,使得系统结构更加简洁。

  3. 系统可能需要动态切换实现:当系统在运行时需要动态选择或切换不同的实现时,桥接模式提供了一种灵活的方式来管理这些实现,从而减少系统的复杂度。

  4. 需要提高系统的可扩展性:桥接模式允许在不影响其他部分的情况下独立地扩展抽象和实现部分。这对于希望在将来轻松地添加新的功能或实现的系统特别有用。

  5. 复杂的对象结构需要灵活的管理:当对象的结构非常复杂,例如,涉及到多个维度的变化时,桥接模式可以将这些维度分开管理,从而提高系统的可维护性和灵活性。

具体应用示例

  1. 图形绘制系统:在绘制不同类型的图形(如圆形、方形等)时,可以将图形的抽象(如如何绘制图形)和具体的绘制实现(如不同的绘图API)分开处理。例如,你可以使用桥接模式来支持不同的绘图API(如OpenGL、DirectX)和不同的图形(如圆形、矩形)组合。

  2. 用户界面(UI)框架:UI框架通常需要支持多个平台(如Windows、macOS、Linux)的具体实现,同时又要保持统一的用户界面设计。桥接模式可以将UI组件的抽象层(如按钮、文本框)与具体的平台实现分离开来,从而使得不同平台上的UI组件可以共享相同的抽象层。

  3. 跨平台开发:在需要跨多个操作系统或硬件平台的应用程序中,桥接模式可以用来将平台特定的实现与应用程序的核心逻辑分开,从而简化跨平台的开发和维护工作。

  4. 持久化层和数据库:当一个系统需要支持多种数据库(如MySQL、PostgreSQL、MongoDB)时,可以使用桥接模式将持久化层的抽象接口与具体的数据库实现分开,从而使得系统能够在不修改持久化逻辑的情况下,轻松切换或扩展数据库支持。

三、桥接模式的设计方法

 bridge.cpp

#include <iostream>
#include <string>

// 定义平台接口
class DrawingAPI {
public:
    virtual void drawButton(const std::string& label, int x, int y, int width, int height) = 0;
    virtual void drawTextBox(const std::string& text, int x, int y, int width, int height) = 0;
    virtual ~DrawingAPI() = default;
};

// 定义具体平台实现
class WindowsAPI : public DrawingAPI {
public:
    void drawButton(const std::string& label, int x, int y, int width, int height) override {
        std::cout << "Windows: Drawing button '" << label << "' at (" << x << ", " << y << ") with size " << width << "x" << height << std::endl;
    }

    void drawTextBox(const std::string& text, int x, int y, int width, int height) override {
        std::cout << "Windows: Drawing text box with text '" << text << "' at (" << x << ", " << y << ") with size " << width << "x" << height << std::endl;
    }
};

class MacOSAPI : public DrawingAPI {
public:
    void drawButton(const std::string& label, int x, int y, int width, int height) override {
        std::cout << "MacOS: Drawing button '" << label << "' at (" << x << ", " << y << ") with size " << width << "x" << height << std::endl;
    }

    void drawTextBox(const std::string& text, int x, int y, int width, int height) override {
        std::cout << "MacOS: Drawing text box with text '" << text << "' at (" << x << ", " << y << ") with size " << width << "x" << height << std::endl;
    }
};

class LinuxAPI : public DrawingAPI {
public:
    void drawButton(const std::string& label, int x, int y, int width, int height) override {
        std::cout << "Linux: Drawing button '" << label << "' at (" << x << ", " << y << ") with size " << width << "x" << height << std::endl;
    }

    void drawTextBox(const std::string& text, int x, int y, int width, int height) override {
        std::cout << "Linux: Drawing text box with text '" << text << "' at (" << x << ", " << y << ") with size " << width << "x" << height << std::endl;
    }
};

// 定义UI组件的抽象层
class UIComponent {
public:
    UIComponent(DrawingAPI* api) : api_(api) {}

    virtual void draw() = 0;

protected:
    DrawingAPI* api_;
};

// 定义具体的UI组件
class Button : public UIComponent {
public:
    Button(const std::string& label, int x, int y, int width, int height, DrawingAPI* api)
        : UIComponent(api), label_(label), x_(x), y_(y), width_(width), height_(height) {}

    void draw() override {
        api_->drawButton(label_, x_, y_, width_, height_);
    }

private:
    std::string label_;
    int x_, y_, width_, height_;
};

class TextBox : public UIComponent {
public:
    TextBox(const std::string& text, int x, int y, int width, int height, DrawingAPI* api)
        : UIComponent(api), text_(text), x_(x), y_(y), width_(width), height_(height) {}

    void draw() override {
        api_->drawTextBox(text_, x_, y_, width_, height_);
    }

private:
    std::string text_;
    int x_, y_, width_, height_;
};


void doWorking() {
    WindowsAPI windowsAPI;
    MacOSAPI macOSAPI;
    LinuxAPI linuxAPI;

    Button windowsButton("Submit", 100, 50, 200, 40, &windowsAPI);
    TextBox windowsTextBox("Enter text", 100, 100, 300, 40, &windowsAPI);

    Button macButton("Submit", 100, 50, 200, 40, &macOSAPI);
    TextBox macTextBox("Enter text", 100, 100, 300, 40, &macOSAPI);
    
    Button linuxButton("Submit", 100, 50, 200, 40, &linuxAPI);
    TextBox linuxTextBox("Enter text", 100, 100, 300, 40, &linuxAPI);

    std::cout << "Drawing Windows UI components:" << std::endl;
    windowsButton.draw();
    windowsTextBox.draw();

    std::cout << "\nDrawing MacOS UI components:" << std::endl;
    macButton.draw();
    macTextBox.draw();
    
    std::cout << "\nDrawing Linux UI components:" << std::endl;
    linuxButton.draw();
    linuxTextBox.draw();
    
    return ;
}

int main() {
	// start working
	doWorking();
	return 0;
}

运行效果

四、总结

在这个示例中:

  • DrawingAPI 是平台接口,定义了绘制方法。
  • WindowsAPI 和 MacOSAPI 、LinuxAPI 是具体实现,提供平台特定的绘制方法。
  • UIComponent 是抽象层,持有DrawingAPI 的引用。
  • Button 和 TextBox 是具体的UI组件,实现了 UIComponent 。

桥接模式通过分离抽象和实现,使得UI组件的抽象层可以与不同的平台实现解耦,从而使得支持新平台或修改现有平台的实现变得更加容易。

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

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

相关文章

PNG的存储方式[计算机原理]

块的基本理论 众所周知&#xff0c;所有的信息在计算机中以位的形式存在&#xff08;0|1&#xff09;8位是一个字节&#xff0c;可以表示成两个16进制数&#xff0c;例如0xFC因为4位对应一个16进制数嘛。PNG这种图片也不例外&#xff0c;它也是由位组成的&#xff0c;不过我们…

利用Redis获取权限的多种方式

更多实战内容&#xff0c;可前往无问社区查看http://www.wwlib.cn/index.php/artread/artid/10333.html Redis是我们在实战中经常接触到的一款数据库&#xff0c;因其在前期打点中被利用后可直接影响服务器安全所以在攻防过程中也备受红队关注&#xff0c;在本文中会重点分享一…

【java】Java Cryptography Extension (JCE)

在Java中&#xff0c;我们可以使用Java Cryptography Extension (JCE) 来实现加密和解密工具和技术。以下是一些常见的加密和解密技术及其示例代码&#xff1a; 1.使用AES加密和解密 package org.example.Test05;import javax.crypto.Cipher; import javax.crypto.spec.Secre…

高效记录与笔记整理的策略:工具选择、结构设计与复习方法

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

【赵渝强老师】基于RBF的HDFS联邦架构

在最新的Hadoop版本中又实现了基于Router的联盟架构&#xff0c;并且在这个架构之上还实现了许多增强集群管理能力的特性。Router将挂载表从客户端中抽离了出来&#xff0c;解决了ViewFS存在的问题。   视频讲解如下&#xff1a; 基于RBF的HDFS联邦架构 【赵渝强老师】基于R…

基于Mediepipe的手势识别系统 | OpenCV | Mediapipe | C++ | QT | Python | C# | Unity

基于Mediapipe的手势识别系统 OpenCV、Mediapipe C (QT)、Python (PyCharm)、C# (Visual Studio) Unity 3D 登录界面 图片手势识别 视频文件手势识别 摄像头实时手势识别 演示视频 基于Mediapipe的手势识别系统

ESP32 分区表介绍

前言 个人邮箱&#xff1a;zhangyixu02gmail.com关于分区表&#xff0c;很多人看了很多资料很可能依旧是一脸懵逼。不知道各位有没有玩过 EEPROM&#xff0c;他可以断电保存数据。这里你也可以理解为分区表将 Flash 中划分出来了一个 EEPROM。虽然这样说从专业的角度是毫无疑问…

Ilya Sutskever 2023年伯克利大学演讲回顾:无监督学习与GPT的数学基础

引言 在2023年&#xff0c;OpenAI联合创始人之一的Ilya Sutskever在伯克利大学进行了一次极具影响力的演讲。这场演讲虽然内容复杂晦涩&#xff0c;但却被认为是人工智能发展历史上的一个重要里程碑。在演讲中&#xff0c;Sutskever深入探讨了无监督学习的数学依据&#xff0c…

即插即用的3D神经元注意算法

在快速发展的人工智能领域&#xff0c;科技的进步往往源于对复杂问题的突破性解决方案。如今&#xff0c;我们正站在一种激动人心的技术创新的前沿——即插即用的3D神经元注意算法。这一前沿技术不仅为计算神经科学提供了全新的视角&#xff0c;也为人工智能的未来打开了新的大…

elementplus 二次封装 select 自定义指令上拉加载更多 完美解决 多次接口调用 重新加载数据多次调用!!!

ps: 我封装的 select 实现了&#xff1a;1、上拉加载更多。2、远程搜索。3、单选多选。4、二次回显之前选择的数据。5、option 里面显示的内容自定义 如果有您想要实现的功能 可以私聊我 本文只讲解上拉触底加载更多 效果&#xff1a;&#xff08;名字都是测试数据 随便乱写…

【数据结构】PTA 链式表的按序号查找 C语言

本题要求实现一个函数&#xff0c;找到并返回链式表的第K个元素。 函数接口定义&#xff1a; ElementType FindKth( List L, int K ); 其中List结构定义如下&#xff1a; typedef struct LNode *PtrToLNode; struct LNode {ElementType Data;PtrToLNode Next; }; typedef P…

Mysql原理与调优-Mysql的内存结构

1.绪论 前面说过InnoDB每次查询数据或者更新数据&#xff0c;都是先以16kb的大小将数据读取到内存中&#xff0c;然后对内存中的数据页进行操作。为了减少磁盘IO&#xff0c;Innodb的会先单独的申请一块连续的空间&#xff0c;将从磁盘中的数据页缓存到这片内存中。这片内存就…

数字化转型下的客户服务创新:智能、便捷、人性化

当今这个日新月异的数字时代&#xff0c;企业的竞争已不再局限于产品或服务的本身&#xff0c;而是延伸到了客户体验的每一个细微之处。数字化转型作为推动这一变革的重要力量&#xff0c;正深刻改变着客户服务的面貌&#xff0c;使之变得更加智能、便捷且充满人性化。 一、数字…

Xilinx 7系列收发器GTX入门讲解

目录 一、前言 二、芯片间数据传输技术发展 2.1 时钟/数据同步方式 三、 7系列GTX/GTH 3.1 GTXE2 3.2 Quad 3.3 GTXE2_CHANNEL 3.4 参考时钟结构 3.4.1 外部参考时钟 3.5 CPLL 3.6 QPLL 四、收发器GTX/GTH 4.1 发送器TX 4.2 接收器RX 4.3 TX与RX全流程分析 五、…

CeresPCL 岭回归拟合(曲线拟合)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 由于在使用最小二乘插值拟合时,会涉及到矩阵求逆的操作,但是如果这个矩阵接近于奇异时,那么拟合的结果就会与我们期望的结果存在较大差距,因此就有学者提出在最小二乘的误差函数中添加正则项,即: 这里我们也可…

Catf1ag CTF Web(一)

前言 Catf1agCTF 是一个面向所有CTF&#xff08;Capture The Flag&#xff09;爱好者的综合训练平台&#xff0c;尤其适合新手学习和提升技能 。该平台由catf1ag团队打造&#xff0c;拥有超过200个原创题目&#xff0c;题目设计注重知识点的掌握&#xff0c;旨在帮助新手掌握C…

Pycharm远程连接服务器调试程序(包含VPN连接)

一、Ubuntu服务器使用指南 1、建立个人账户&#xff1a; sudo adduser yourname 2、个人账户中建立conda环境 1&#xff09;将anaconda\miniconda安装包上传到服务器home\yourname目录下 2&#xff09;bash安装miniconda 3&#xff09;source .bashrc激活 3、MobaXterm连…

Spring Cloud Gateway 请求转发源码分析

一、背景 Spring Cloud Gateway 作为一种微服务网关组件&#xff0c;相信大家都不陌生&#xff0c;一个请求经过Spring Cloud Gateway是如何转发出去的&#xff0c;今天我们就来分析一下这部分的源码。 二、正文 下面这张图大家在学习Spring Cloud Gateway的时候肯定见过&am…

NASA数据集:DC-8 飞机上收集测量数据(冰原和永久冻土融化、雪反照率降低以及海盐气溶胶)

ARCTAS DC-8 Aircraft Merge Data 简介 ARCTAS_Merge_DC8_Aircraft_Data 是在 "从飞机和卫星收集对流层成分的北极研究 "亚轨道活动期间&#xff0c;从 DC-8 飞机上收集测量数据的各种现场仪器中预先生成的合并文件。该产品的数据收集工作已经完成。 北极是了解气…

网络编程-阻塞、非阻塞、多路复用、Selector对于accept、read、write事件监听实现详解

阻塞 理论 阻塞模式下&#xff0c;相关方法&#xff08;accept、read、write&#xff09;都会导致线程暂停。 ServerSocketChannel.accept 会在没有连接建立时让线程暂停。SocketChannel.read 会在没有数据可读时让线程暂停。阻塞的表现其实就是线程暂停了&#xff0c;暂停期…