桥接模式和组合模式的区别

        桥接模式(Bridge Pattern)和组合模式(Composite Pattern)都是结构型设计模式,旨在解决对象结构的复杂性问题,但它们的应用场景和目的有所不同。以下是它们的区别:

1. 定义与目的

桥接模式(Bridge Pattern):

  • 定义:将抽象部分与它的实现部分分离,使它们可以独立地变化。
  • 目的:主要解决在多维度变化情况下,类的爆炸性增长问题。通过将两个或多个维度的变化分离到不同的类层次中,从而使得系统更具灵活性。

组合模式(Composite Pattern):

  • 定义:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
  • 目的:主要解决对象的层次结构问题,使得客户端可以一致地处理单个对象和组合对象。

2. 主要使用场景

桥接模式:

  • 当一个类有多个变化维度,并且这些维度需要独立变化时使用桥接模式。例如,一个图形类可能有形状和颜色两个变化维度,那么可以将形状和颜色分离为两个独立的层次结构。
  • 当不希望在抽象和实现之间产生紧耦合时。

组合模式:

  • 当需要表示对象的部分-整体层次结构时使用组合模式。
  • 当希望客户端可以统一地处理单个对象和组合对象时。

3. 结构区别

        桥接模式:包含两个独立的层次结构,一个是抽象部分,一个是实现部分。抽象部分包含对实现部分的引用。

        组合模式:包含一个对象树的层次结构,叶子节点表示基本对象,组合节点表示容器对象。容器对象可以包含叶子节点或其他容器节点。

4. 示例代码对比

桥接模式(Bridge Pattern)

        目的:将抽象部分与它的实现部分分离,使它们可以独立地变化。

类比

        想象一下,你在设计一种绘图应用程序,这个应用程序可以绘制不同种类的形状(例如,圆形和方形),而每种形状可以用不同的颜色来绘制(例如,红色和蓝色)。在这种情况下,形状与颜色是两个独立的维度。

如果不用桥接模式,你可能会为每种情况创建一个类:

  • 红色的圆形
  • 蓝色的圆形
  • 红色的方形
  • 蓝色的方形

        这样类的数量会随着形状和颜色的增加而成倍增长(组合爆炸)。

桥接模式的解决方案:

        将形状和颜色分开处理。你创建一个形状的抽象类,并且它包含一个颜色的接口。然后你可以独立地扩展形状和颜色。

// 颜色接口
class Color {
public:virtual std::string fill() const = 0;virtual ~Color() = default;
};class Red : public Color {
public:std::string fill() const override {return "红色";}
};class Blue : public Color {
public:std::string fill() const override {return "蓝色";}
};// 形状抽象类
class Shape {
protected:std::shared_ptr<Color> color;
public:Shape(std::shared_ptr<Color> col) : color(col) {}virtual std::string draw() const = 0;virtual ~Shape() = default;
};class Circle : public Shape {
public:Circle(std::shared_ptr<Color> col) : Shape(col) {}std::string draw() const override {return "绘制一个" + color->fill() + "的圆形";}
};class Square : public Shape {
public:Square(std::shared_ptr<Color> col) : Shape(col) {}std::string draw() const override {return "绘制一个" + color->fill() + "的方形";}
};// 使用
int main() {std::shared_ptr<Color> red = std::make_shared<Red>();std::shared_ptr<Color> blue = std::make_shared<Blue>();std::shared_ptr<Shape> redCircle = std::make_shared<Circle>(red);std::shared_ptr<Shape> blueSquare = std::make_shared<Square>(blue);std::cout << redCircle->draw() << std::endl; // 输出: 绘制一个红色的圆形std::cout << blueSquare->draw() << std::endl; // 输出: 绘制一个蓝色的方形return 0;
}

组合模式(Composite Pattern)

        目的:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

类比

        想象一下,你在设计一个公司组织架构,这个组织架构中有部门和员工。部门可以包含子部门和员工,子部门又可以包含员工或更多的子部门,形成一个树形结构。

组合模式的解决方案:

        你创建一个通用的组件接口,它可以表示部门和员工,然后通过组合对象来表示部门,通过叶子对象来表示员工。

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>// 组件接口
class Employee {
public:virtual void showDetails() const = 0;virtual void add(std::shared_ptr<Employee> employee) {}virtual void remove(std::shared_ptr<Employee> employee) {}virtual ~Employee() = default;
};// 叶子节点
class Developer : public Employee {
private:std::string name;
public:Developer(const std::string& devName) : name(devName) {}void showDetails() const override {std::cout << "开发者: " << name << std::endl;}
};// 叶子节点
class Designer : public Employee {
private:std::string name;
public:Designer(const std::string& desName) : name(desName) {}void showDetails() const override {std::cout << "设计师: " << name << std::endl;}
};// 容器节点
class Manager : public Employee {
private:std::string name;std::vector<std::shared_ptr<Employee>> subordinates;
public:Manager(const std::string& mgrName) : name(mgrName) {}void showDetails() const override {std::cout << "经理: " << name << std::endl;for (const auto& subordinate : subordinates) {subordinate->showDetails();}}void add(std::shared_ptr<Employee> employee) override {subordinates.push_back(employee);}void remove(std::shared_ptr<Employee> employee) override {subordinates.erase(std::remove(subordinates.begin(), subordinates.end(), employee), subordinates.end());}
};// 使用
int main() {std::shared_ptr<Employee> dev1 = std::make_shared<Developer>("Alice");std::shared_ptr<Employee> dev2 = std::make_shared<Developer>("Bob");std::shared_ptr<Employee> des1 = std::make_shared<Designer>("Charlie");std::shared_ptr<Manager> mgr1 = std::make_shared<Manager>("Dave");mgr1->add(dev1);mgr1->add(dev2);mgr1->add(des1);std::shared_ptr<Employee> des2 = std::make_shared<Designer>("Eve");std::shared_ptr<Manager> generalManager = std::make_shared<Manager>("Frank");generalManager->add(mgr1);generalManager->add(des2);generalManager->showDetails();// 输出:// 经理: Frank// 经理: Dave// 开发者: Alice// 开发者: Bob// 设计师: Charlie// 设计师: Evereturn 0;
}

总结

  • 桥接模式:
    • 用于分离抽象和实现,使它们可以独立变化。
    • 适用于多维度变化的场景,如形状和颜色的组合。
  • 组合模式:
    • 用于构建对象的树形结构,使得单个对象和组合对象可以一致地处理。
    • 适用于表示部分-整体层次结构的场景,如公司组织架构。

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

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

相关文章

Qt 小项目 学生管理信息系统

主要是对数据库的增删查改的操作 登录/注册界面&#xff1a; 主页面&#xff1a; 添加信息&#xff1a; 删除信息&#xff1a; 删除第一行&#xff08;支持多行删除&#xff09; 需求分析&#xff1a; 用QT实现一个学生管理信息系统&#xff0c;数据库为MySQL 要求&#xf…

14.数据容器-set集合

特点 无序的&#xff0c;元素不重复&#xff0c;自带去重功能。 可以容纳不同类型的元素数据。 # 定义一个空set my_set {} your_set set() my_set {aa, bb, bb, aa} # {aa, bb} print(my_set) 因为set集合是无序的&#xff0c;所以集合不支持下标索引访问。所以set集合…

“量子跃迁与数据织网:深入探索K最近邻算法在高维空间中的优化路径、神经网络融合技术及未来机器学习生态系统的构建“

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

硬件选型规则

光源选型: 先用型号中带H的&#xff0c;没有的选标准的. 光源和光源控制器的搭配需要确保接口一致。 根据型号表中的最佳工作距离和相机的尺寸。 光源控制器选型&#xff1a; 首先选择海康风格系列光源控制器考虑与光源的接口匹配。功率应该满足接近光源功率。检查是否退市…

【QNX+Android虚拟化方案】135 - QNX侧如何Dump 88Q5152 MIBS报文计数

【QNX+Android虚拟化方案】135 - QNX侧如何Dump 88Q5152 MIBS报文计数 一、读取 88Q5152 MIBS 计数二、读取 88Q5152 WDT 相关寄存器基于原生纯净代码,自学总结 纯技术分享,不会也不敢涉项目、不泄密、不传播代码文档!!! 本文禁止转载分享 !!! 汇总链接:《【QNX+Andro…

C#核心(15)继承中的构造函数

前言 我们之前学过构造函数是什么东西&#xff0c;今天的内容也和构造函数紧密相关&#xff0c;一个继承了父亲的子类里面构造函数的规则是什么样的&#xff0c;今天内容很简单&#xff0c;请听我慢慢讲来。 基本概念 特点&#xff1a;当申明一个子类时&#xff0c;先执行父…

TVbox源贡献指南

欢迎各路大佬踊跃提PR&#xff0c;分享爬虫代码。 源码仓库地址 https://github.com/lushunming/AndroidCatVodSpider 快速开始 本工程是一个完整的AndroidStudio工程&#xff0c;请你用AS打开编辑。 工程调试完毕后要需要导出生成jar文件配合软件使用&#xff0c;执行根目…

FastAPI快速入门

文章目录 了解FastAPI程序结构第一步&#xff0c;导入FastAPI第二步&#xff0c;创建一个app实例第三步&#xff0c;编写一个 路径操作装饰器第五步、运行开发服务器uvicorn main:app --reload即可访问api链接。符案例 声明路径参数声明路径参数的类型get请求查询参数请求体如何…

云计算.运维.面试题

1、计算机能直接识别的语言( C )。 A、汇编语言 B、自然语言 C、机器语言 D、高级语言 2、应用软件是指( D )。 A、所有能够使用的软件 B、能被各应用单位共同使用的某种软件 C、所有计算机上都应使用的基本软件D、专门为某一应用目的而编制的软件 3、计算机的显示器是一…

如何优雅地实现单例模式?内部静态类还是双重检查锁定?

在最近的一个项目中&#xff0c;我需要为一个核心配置类实现单例模式。在设计过程中&#xff0c;我发现要同时满足延迟加载和线程安全这两个要求&#xff0c;常见的实现方式有两种&#xff1a;内部静态类和双重检查锁定&#xff08;Double-Checked Locking, DCL&#xff09;。 …

【计算机网络】 —— 数据链路层(壹)

文章目录 前言 一、概述 1. 基本概念 2. 数据链路层的三个主要问题 二、封装成帧 1. 概念 2. 帧头、帧尾的作用 3. 透明传输 4. 提高效率 三、差错检测 1. 概念 2. 奇偶校验 3. 循环冗余校验CRC 1. 步骤 2. 生成多项式 3. 例题 4. 总结 四、可靠传输 1. 基本…

golang实现简单的redis服务

golang 手搓redis服务器仓库地址:实现思路: golang 手搓redis服务器 仓库地址: 仓库: https://github.com/dengjiayue/my-redis.git 实现思路: ● 协议: tcp通信 ● 数据包: 长度(4byte)方法(1byte)数据json ● 数据处理: 单线程map读写 ○ 依次处理待处理队列的请求(chan)…

智慧银行反欺诈大数据管控平台方案(八)

智慧银行反欺诈大数据管控平台的核心理念&#xff0c;在于通过整合先进的大数据技术、算法模型和人工智能技术&#xff0c;构建一个全面、智能、动态的反欺诈管理框架&#xff0c;以实现对金融交易的全方位监控、欺诈行为的精准识别和高效处理。这一理念强调数据驱动决策&#…

3D 生成重建019-LERF用文本在Nerf中开启上帝之眼

3D 生成重建019-LERF用文本在Nerf中开启上帝之眼 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 人类利用自然语言描述物理世界&#xff0c;根据各种特性&#xff08;视觉外观、语义、抽象关联&#xff09;寻找具体的3D位置。在这项工作中&#xff0c;作者提出了语言嵌…

如何选择合适的期刊投稿?从课题组经验到在线工具的使用全解析

~~~本文是作者个人的经验分享&#xff0c;建立在导师让自己选刊的情况下~~~ 投稿选刊是科研过程中至关重要的一步&#xff0c;选刊过程可能让许多初投稿的研究者感到迷茫和困惑&#xff1a;期刊那么多&#xff0c;如何找到最合适的&#xff1f; 本文将从多个角度介绍如何选择投…

024、Docker与SSH在分布式系统中的实践指南

1. Docker SSH配置最佳实践 Docker容器通常不需要SSH服务来运行&#xff0c;因为它们设计为轻量级、无状态的&#xff0c;并且通常通过Docker命令行界面与宿主机进行交互。但是&#xff0c;在某些情况下&#xff0c;您可能需要通过SSH访问Docker容器进行调试、维护或其他操作。…

【kafka】消息队列的认识,Kafka与RabbitMQ的简单对比

什么是消息队列&#xff1f; 消息队列&#xff08;Message Queue&#xff0c;简称 MQ&#xff09;是一个在不同应用程序、系统或服务之间传递数据的机制。 它允许系统间异步地交换信息&#xff0c;而无需直接交互&#xff0c;确保消息的可靠传输。 想象一下&#xff0c;你正在…

.NET MAUI与.NET for Android/IOS的关系

2024年11月13日微软发布了.Net9.0,我打算体验一下。安装好.Net9.0 SDK后发现Visual Studio识别不到9.0&#xff0c;但是通过命令行dotnet --info查看是正常的&#xff0c;后面看到了VS有版本可以升级&#xff0c;把VS升级到17.12.0就可以了。更新完打开以后看到如下界面 这里…

SqlDataAdapter

SqlDataAdapter 是 .NET Framework 和 .NET Core 中提供的一个数据适配器类&#xff0c;属于 System.Data.SqlClient 命名空间&#xff08;或在 .NET 6 中属于 Microsoft.Data.SqlClient 命名空间&#xff09;。它的作用是充当数据源&#xff08;如 SQL Server 数据库&#xff…

【vivado】时序报告--best时序和worst时序

利用vivado进行开发时&#xff0c;生成best时序报告和worst时序报告。 best时序报告 slow选择min_max&#xff0c;fast选择none。 worst时序报告 fast选择min_max&#xff0c;slow选择none。