C++设计模式——Bridge桥接模式

news2024/12/28 17:38:26

一,桥接模式简介

桥接模式是一种结构型设计模式,用于将抽象与实现分离,这里的"抽象"和"实现"都有可能是接口函数或者类。

桥接模式让抽象与实现之间解耦合,使得开发者可以更关注于实现部分,调用者(Client)可以更关注于抽象部分。

桥接模式可以将一个复杂的类进行拆分为好几个类,开发者可以修改其中任意一个类的实现,而不影响其他类的正常运行,该模式可以降低代码的维护工作量,降低代码风险。

桥接模式的核心就是:抽象化(Abstraction)与实现化(Implementation)

抽象化:忽略一些细节,将具有共同特征的不同实体抽象为同一个对象。

实现化:为抽象化提供具体的逻辑和代码实现。

举个例子:

假设有一堆几何体,这些几何体有形状、颜色等特征,形状有:矩形、圆形,颜色有:红色、蓝色。

为了使用类来描述这些几何体,我们可以将他们抽象为四个子类:红色矩形,蓝色矩形,红色圆形,蓝色圆形。

按照以上方式,如果几何体还包含更多种类的形状和颜色,例如椭圆、绿色,那么这些特征通过排列组合产生的子类将会呈指数级增长。如果此时使用桥接模式,将会大大降低类与类之间的耦合,减少了开发期间的代码量。

对应UML类图:

桥接模式将继承关系改为组合关系,对于以上几何体的描述,我们使用一个类来描述几何体的矩形、圆形等形状,我们使用另一个类来描述几何体的红色、蓝色等颜色,最后将这两个类的实例进行组合。当需要改变类的颜色或形状的实现时,无需修改整个类的实现,只需要修改颜色或形状的实现即可。

对应UML类图:

二,桥接模式的结构

桥接模式主要涉及的类:
1. 抽象角色类:是一个类,定义了统一的对外接口,并定义了接口的组成结构,但是不包含接口对应的具体实现。
2. 具体实现类:是一个或多个类,该类包含了对抽象角色类的接口的具体代码实现。这些类可以根据需求变化而独立变化,且不会影响到其他类的功能。具体实现类与抽象角色类之间的关联方式采用的是组合而非继承。
3. 桥接类:充当了抽象角色类和具体实现类之间的桥梁,负责维护抽象角色类和具体实现类之间的关系,它允许客户端在运行时选择使用哪个具体实现类。
桥接模式的主要组件:
1.Abstraction:抽象类,提供统一的抽象接口。内部包含对Implementor类对象的引用。
2.RefinedAbstraction:扩充抽象类,有的教程里面称为"ExtendedAbstraction",Abstraction的子类,扩充Abstraction的抽象接口。
3.Implementor:实现类,提供了实现类的接口,这个接口的功能和以上的抽象接口不同。
4.ConcreteImplementor:提供了实现类的接口对应的代码逻辑。
桥接模式UML类图:

代码实现: 

#include <iostream>

class Implementation {
public:
    virtual ~Implementation() {}
    virtual std::string newOperation() const = 0;
};

class ConcreteImplementationA : public Implementation {
public:
    std::string newOperation() const override {
        return "ConcreteImplementationA: Here's the result on the platform A.\n";
    }
};
class ConcreteImplementationB : public Implementation {
public:
    std::string newOperation() const override {
        return "ConcreteImplementationB: Here's the result on the platform B.\n";
    }
};

class Abstraction {
protected:
    Implementation* implementation_;

public:
    Abstraction(Implementation* implementation) : implementation_(implementation) {
    }

    virtual ~Abstraction() {
    }

    virtual std::string doOperation() const {
        return "Abstraction: Base operation with:\n" +
            this->implementation_->newOperation();
    }
};

class RefinedAbstraction : public Abstraction {
public:
    RefinedAbstraction(Implementation* implementation) : Abstraction(implementation) {
    }
    std::string doOperation() const override {
        return "RefinedAbstraction: Extended operation with:\n" +
            this->implementation_->newOperation();
    }
};

void ClientCode(const Abstraction& abstraction) {
    std::cout << abstraction.doOperation();
}

int main() {
    Implementation* implementation_1 = new ConcreteImplementationA;
    Abstraction* abstraction_1 = new Abstraction(implementation_1);
    ClientCode(*abstraction_1);
    std::cout << std::endl;
    delete implementation_1;
    delete abstraction_1;

    Implementation* implementation_2 = new ConcreteImplementationB;
    Abstraction* abstraction_2 = new RefinedAbstraction(implementation_2);
    ClientCode(*abstraction_2);

    delete implementation_2;
    delete abstraction_2;

    return 0;
}

运行结果: 

Abstraction: Base operation with:
ConcreteImplementationA: Here's the result on the platform A.

RefinedAbstraction: Extended operation with:
ConcreteImplementationB: Here's the result on the platform B.

三,桥接模式的应用场景

系统组件升级:当需要为现有系统增加新功能或替换已有功能,但又不希望改变原有接口时。

跨平台应用开发:使用桥接模式来处理不同操作系统或硬件平台的差异,例如在移动端APP应用中,UI组件同时兼容ios和Android平台。

第三方插件开发:使用桥接模式开发出可支持多种第三方服务的组件,例如移动支付api。

API扩展:当API的功能需要被扩展,又希望保持原有API的稳定时,使用桥接模式可以隐藏实现细节。

四,桥接模式的优缺点

桥接模式的优点:

分离接口的抽象与实现部分。

替代了继承的实现方式,代码的可复用性更强。

桥接模式可以修改任意一个模块的功能实现而不影响整个系统。

可以向用户隐藏实现细节。

降低了类之间的依赖性。

代码的可维护性很强,可以根据需求灵活地更换实现模块。

桥接模式的缺点:

引入了额外的抽象层,使系统变得更复杂。

会额外增加系统的理解与设计难度。

接口调用增多,带来额外的性能开销。

五,代码实战

代码实战: 

生产不同颜色和不同车型的汽车

#include<iostream>
#include<string>

using namespace std;

class IColor
{
public:
    virtual string Color() = 0;
};

class RedColor : public IColor
{
public:
    string Color()
    {
        return "of Red Color";
    }
};

class BlueColor : public IColor
{
public:
    string Color()
    {
        return "of Blue Color";
    }
};

class ICarModel
{
public:
    virtual string WhatIsMyType() = 0;
};

class Model_A : public ICarModel
{
    IColor* _myColor;
public:
    Model_A(IColor *obj) :_myColor(obj){}
    string WhatIsMyType()
    {
        return "I am a Model_A " + _myColor->Color();
    }
};

class Model_B : public ICarModel
{
    IColor* _myColor;
public:
    Model_B(IColor *obj) :_myColor(obj){}
    string WhatIsMyType()
    {
        return "I am a Model_B " + _myColor->Color();;
    }
};

int main()
{
    IColor* red = new RedColor();
    IColor* blue = new BlueColor();

    ICarModel* modelA = new Model_B(red);
    ICarModel* modelB = new Model_A(blue);

    cout << "\n" << modelA->WhatIsMyType();
    cout << "\n" << modelB->WhatIsMyType() << "\n\n";

    delete red;
    delete blue;
    return 0;
}

运行结果:


I am a Model_B of Red Color
I am a Model_A of Blue Color

六,参考阅读

https://refactoring.guru/design-patterns/bridge

https://design-patterns.readthedocs.io/zh-cn/latest/structural_patterns/bridge.html

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

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

相关文章

谷粒商城实战(036 k8s集群学习2-集群的安装)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第343p-第p345的内容 k8s 集群安装 kubectl --》命令行操作 要进入服务器 而且对一些不懂代码的产品经理和运维人员不太友好 所以我们使用可视化…

【5.x】ELK日志分析

ELK日志分析 一、ELK概述 1、ELK简介 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将ElasticSearch、Logstash和Kiabana三个开源工具配合使用&#xff0c;完成更强大的用户对日志的查询、排序、统计需求。 一个完整的集中式日志系统&#xff0c;需要包含以下几个主…

Java | Leetcode Java题解之第149题直线上最多的点数

题目&#xff1a; 题解&#xff1a; class Solution {public int maxPoints(int[][] points) {int n points.length;if (n < 2) {return n;}int ret 0;for (int i 0; i < n; i) {if (ret > n - i || ret > n / 2) {break;}Map<Integer, Integer> map ne…

SpringBoot系列——使用Spring Cache和Redis实现查询数据缓存

文章目录 1. 前言2. 缓存2.1 什么是缓存2.2 使用缓存的好处2.3 缓存的成本2.4 使用Spring Cache和Redis的优点 3. Spring Cache基础知识3.1 Spring Cache的核心概念3.2 Spring Cache的注解3.2.1 SpEL表达式3.2.2 Cacheable3.2.3 CachePut3.2.4 CacheEvict 4. 实现查询数据缓存4…

eclipse创建maven项目

第一步&#xff1a;打开eclipse 我们选择java项目即可 点击finish即可 它会自动下载插件 然后在控制台上输入Y即可

C语言 | Leetcode C语言题解之第150题逆波兰表达式求值

题目&#xff1a; 题解&#xff1a; int evalRPN(char** tokens, int tokensSize) {int n tokensSize;int stk[(n 1) / 2];memset(stk, 0, sizeof(stk));int index -1;for (int i 0; i < n; i) {char* token tokens[i];if (strlen(token) > 1 || isdigit(token[0])…

LeetCode | 28.找出字符串中第一个匹配项的下标 KMP

这是字符串匹配问题&#xff0c;朴素做法是两重遍历&#xff0c;依次从主串的i位置开始查看是否和模式串匹配&#xff0c;若不匹配就换下一个位置进行判断&#xff0c;直到找到或者遍历完&#xff0c;时间复杂度 O ( m n ) O(m \times n) O(mn) 还可以对主串进行处理&#xff…

Django 5 Web应用开发实战

文章目录 一、内容简介二、目录内容三、值得一读四、适读人群 一、内容简介 《Django 5 Web应用开发实战》集Django架站基础、项目实践、开发经验于一体&#xff0c;是一本从零基础到精通Django Web企业级开发技术的实战指南。《Django 5 Web应用开发实战》内容以Python 3.x和…

边坡监测规范:确保边坡工程安全稳定的专业准则

边坡工程是土木工程中不可或缺的一部分&#xff0c;其安全性直接关系到工程整体的质量与稳定性。因此&#xff0c;在边坡工程中实施有效的监测措施&#xff0c;遵循一系列专业的监测规范&#xff0c;对于预防边坡失稳、滑坡等灾害的发生&#xff0c;保障人民群众的生命财产安全…

Leetcode 力扣119. 杨辉三角 II (抖音号:708231408)

给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1]示例 2: 输入: rowIndex 0 输出: [1]示例 3: 输入: rowIndex 1 输出: [1,1]提示…

Golang | Leetcode Golang题解之第150题逆波兰表达式求值

题目&#xff1a; 题解&#xff1a; func evalRPN(tokens []string) int {stack : make([]int, (len(tokens)1)/2)index : -1for _, token : range tokens {val, err : strconv.Atoi(token)if err nil {indexstack[index] val} else {index--switch token {case ""…

Java | Leetcode Java题解之第150题逆波兰表达式求值

题目&#xff1a; 题解&#xff1a; class Solution {public int evalRPN(String[] tokens) {int n tokens.length;int[] stack new int[(n 1) / 2];int index -1;for (int i 0; i < n; i) {String token tokens[i];switch (token) {case "":index--;stack…

【ElasticSearch】windows server 2019安装ES8.9.1 + kibana8.9.1 + IK分词器

目录 准备工作 ES Kibana IK 安装 es es访问测试 将es安装为系统服务 Kibana 配置es 运行kibana 访问测试 IK 补充 准备工作 ES8.9.1 kibana8.9.1 IK的版本最好要对应上&#xff01;&#xff01;&#xff01; ES es8.9.1&#xff1a; https://artifa…

[大模型]Phi-3-mini-4k-Instruct Lora 微调

本节我们简要介绍如何基于 transformers、peft 等框架&#xff0c;对 Phi-3-mini-4k-Instruct 模型进行 Lora 微调。Lora 是一种高效微调方法&#xff0c;深入了解其原理可参见博客&#xff1a;知乎|深入浅出 Lora。 这个教程会在同目录下给大家提供一个 nodebook 文件&#x…

简单了解RS485与RS232(UART)

简单了解RS485与RS232&#xff08;UART&#xff09; 一、UART和RS232、RS485的关系1、UART2、RS232/RS4853、RS232 与 RS485 的区别与联系 二、Modbus协议说明1、什么是协议2、Modbus协议说明3、Modebus通信过程4、Modbus存储区5、Modbus协议类型6、Modbus功能码 三、stm32HC-S…

【StableDiffusion】采样方法对比优缺点及评估,采样器 调度器(目前已有的 采样器介绍与评估)

采样器 Sampler 采样方法 决定了 如何从 噪声 生成 图像 的过程&#xff0c;也就是去噪过程如何进行 包含 DPM 的采样方法&#xff08;逆转扩散采样&#xff09; DPM → Diffusion Probabilistic Models&#xff08;扩散概率模型&#xff09; DPM、DPM2 包含 DPM 的采样方…

FastAPI 作为H5中流式输出的后端

FastAPI 作为H5中流式输出的后端 最近大家都在玩LLM&#xff0c;我也凑了热闹&#xff0c;简单实现了一个本地LLM应用&#xff0c;分享给大家&#xff0c;百分百可以用哦&#xff5e;^ - ^ 先介绍下我使用的三种工具&#xff1a; Ollama&#xff1a;一个免费的开源框架&…

Redisson原理解析

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

智能对话画画音乐创作歌曲三合一系统源码 前后端分离 附带完整的源代码包+搭建部署教程

系统概述 创想无界是一个高度集成的创意生态系统&#xff0c;它巧妙地融合了人工智能的三大核心领域&#xff1a;自然语言处理&#xff08;NLP&#xff09;用于智能对话&#xff0c;计算机视觉&#xff08;CV&#xff09;实现自动画画&#xff0c;以及音乐生成算法来创作个性化…

Redis中的Lua脚本

EVAL 命令 命令格式 EVAL script numkeys key [key ...] arg [arg ...]命令说明 1、script 参数&#xff1a; 一段Lua脚本程序&#xff0c;会在Redis服务器上下文中运行&#xff0c;不需要&#xff08;也不应该&#xff09;定义为一个Lua函数。 2、numkeys 参数&#xff1…