当前位置: 首页 > news >正文

【设计模式】Head First 设计模式——桥模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。

设计思想

桥模式。将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。

动机

某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。

桥模式能够应对这种「多维度的变化」,轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度。

img

  • Abstraction Implementor为稳定的基础功能(根据维度划分为多个模块,维度影响的部分独立封装)
  • RefinedAbstractionw为第一个变化维度(Abstraction中的成员)
  • ConcreteImplementor为第二个变化维度(Implementor中的成员)

Bridge使用「对象间的组合关系」解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化,即“子类化”它们。

Bridge有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。

Bridge的应用一般在「两个非常强的变化维度」,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。

业务场景

你打算设计一款聊天软件Message,并打算推出两个版本:PC端版本,移动端版本,由于平台差异,所以实现具体功能的时候也会有差异。并且未来计划在两个平台上都推出两个应用版本,一个是完美版,一个是轻量Lite版。你会怎么设计?

如果应用继承去实现,先设计一个基类Message(这个Message里有一些东西是不因平台差异而变化的,比如登录,发送功能,但是有些是不一样的,比如播放声音,键入文字等),然后由于有两个平台,所以设计两个类:PCMessage, MobileMessage 继承这个Message类,然后又由于你要推出两个版本:完美版和Lite轻量版,所以又要设计两个类去分别继承PCMessage, MobileMessage类,最终的类图大概如下:

在这里插入图片描述

不难发现,这个案例中有两个维度的变化:平台不同,版本不同在影响着你的软件。如果你的软件要登录m个平台,1个软件要推出n个版本,那么最终如果采用继承,你就要设计并实现1+m+m*n个类,随着你的软件的功能迭代,版本迭代以及登录平台的增加,到最后就会造成子类爆炸。这是一个失败的设计。

而桥模式则给出了问题的答案:

代码案例

class Messager{
protected:MessagerImp* messagerImp;//平台
public:virtual void Login(string username, string password)=0;virtual void SendMessage(string message)=0;virtual void SendPicture(Image image)=0;virtual ~Messager(){}
};
// 不同的变化方向(业务和平台),所以分为两个类
class MessagerImp{
public:virtual void PlaySound()=0;virtual void DrawShape()=0;virtual void WriteText()=0;virtual void Connect()=0;virtual MessagerImp(){}
};
//平台实现 n
class PCMessagerImp : public MessagerImp{
public:virtual void PlaySound(){...}virtual void DrawShape(){...}virtual void WriteText(){...}virtual void Connect(){...}
};
class MobileMessagerImp : public MessagerImp{
public://具体实现virtual void PlaySound(){...}virtual void DrawShape(){...}virtual void WriteText(){...}virtual void Connect(){...}
};
//业务抽象 m
class MessagerLite :public Messager {
public:virtual void Login(string username, string password){messagerImp->Connect();//........}virtual void SendMessage(string message){messagerImp->WriteText();//........}virtual void SendPicture(Image image){messagerImp->DrawShape();//........}
};
class MessagerPerfect  :public Messager { 
public:  virtual void Login(string username, string password){messagerImp->PlaySound();//********messagerImp->Connect();//........}virtual void SendMessage(string message){messagerImp->PlaySound();//********messagerImp->WriteText();//........}virtual void SendPicture(Image image){messagerImp->PlaySound();//********messagerImp->DrawShape();//........}
};
void Process(){//运行时装配MessagerImp* mImp=new PCMessagerImp();Messager *m =new Messager(mImp);
}

相关文章:

【设计模式】Head First 设计模式——桥模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 设计思想 桥模式。将抽象部分(业务功能)与实现部分(平…...

CESM2代码下载

这半年忙着毕业写论文,好久好久好久不更新了∠( ω)/ ,今天准备开个新坑 ๑乛◡乛๑,学习一下CESM(Community Earth System Model),它是一个完全耦合的全球气候模型,可用于地球过去、…...

编写OpenCL程序的基本步骤

opencl pyopencl OpenCL-Headers OpenCL(全称为Open Computing Langugae,开放运算语言)是第一个面向异构系统(此系统中可由CPU,GPU或其它类型的处理器架构组成)的并行编程的开放式标准。 它是跨平台的。 OpenCL由两部分组成,一是用于编写…...

计算机网络之TCP/IP协议第一篇:网络基础知识

文章目录 写给自己的话 一:前言 1:手握金刚钻的TCP/IP 2:计算机中的协议 3:分组...

虚拟机扩容

系统环境centos8,分两步,第一步先在vmware扩容,第二部在虚拟机内部扩容 1.vmware分配磁盘空间 2.虚拟机内部扩容 查看当前磁盘信息,这个是扩容之前的,扩容完成才会显示新的 df -h查看系统分区信息 fdisk -l查看目录…...

Linux下的系统编程——进程间的通信(九)

一、进程间通信常用方式 IPC方式: Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核&am…...

Qt QtableWidget、QtableView表格删除选中行、删除单行、删除多行

文章目录 Qt QtableWidget表格删除选中行只能选择一行,点击按钮后,删除一行可以选择中多行,点击按钮后,删除多行选中某一列中的不同行,点击按钮后,删除多行 QTableWidgetSelectionRange介绍QTableWidget的选…...

【代码随想录day24】不同的二叉搜索树

题目 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n 3 输出:5示例 2: 输入:n 1 输出&#xf…...

数学建模--Subplot绘图的Python实现

目录 1.Subplot函数简介 2.Subplot绘图范例1:绘制规则子图 3.Subplot绘图范例2:绘制不规则子图 4.Subplot绘图范例3:gridspec辅助实战1 5.Subplot绘图范例4:gridspec辅助实战2 1.Subplot函数简介 """ 最近在数学建模种需要绘制多张子图,发现对于subplot函…...

JMeter(三十九):selenium怪异的UI自动化测试组合

文章目录 一、背景二、JMeter+selenium使用过程三、总结一、背景 题主多年前在某社区看到有人使用jmeter+selenium做UI自动化测试的时候,感觉很是诧异、怪异,为啥?众所周知在python/java+selenium+testng/pytest这样的组合框架下,为啥要选择jmeter这个东西[本身定位是接口测…...

c++ 移动构造方法为什么要加noexcept

背景: 最近看了候捷老师的c的教程, 他说移动构造方法要加noexcept, 在vector扩容的时候, 如果有移动构造方法没有加noexcept,是不会调用的. 个人感觉有些神奇, 这就去查下一探究竟. 过程: 测试代码如下: #include <iostream> #include <vector> struct A {A(){s…...

鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…...

手把手教你搭建园林园艺小程序商城

现如今&#xff0c;随着互联网的快速发展&#xff0c;小程序成为了企业和个人展示产品和服务的新方式。在园林园艺行业&#xff0c;构建一个园林园艺小程序能够更好地推广和销售自己的产品和服务。那么&#xff0c;如何构建一个园林园艺小程序呢&#xff1f;下面我们来详细介绍…...

Java Iterator(迭代器)

Java迭代器&#xff08;Iterator&#xff09;是 Java 集合框架中的一种机制&#xff0c;是一种用于遍历集合&#xff08;如列表、集合和映射等&#xff09;的接口。 它提供了一种统一的方式来访问集合中的元素&#xff0c;而不需要了解底层集合的具体实现细节。 Iterator 是 …...

Logstash同步MySQL数据到ElasticSearch

当MySQL数据到一定的数量级&#xff0c;而且索引不能实现时&#xff0c;查询就会变得非常缓慢&#xff0c;所以使用ElasticSearch来查询数据。本篇博客介绍使用Logstash同步MySQL数据到ElasticSearch&#xff0c;再进行查询。 测试环境 Windows系统MySQL 5.7Logstash 7.0.1El…...

【C++】运算符重载的示例实现和应用

C运算符重载的格式&#xff1a; operator 运算符 比如要重载 ! 运算符 &#xff1a; operator ! 下面是一个例子&#xff1a; class DemoText{DemoText(string str, int num){m_text str; m_number num;}string m_text;int m_number; }这里来定义两个对象&#xff1a;…...

Kubernetes禁止调度

在Kubernetes中&#xff0c;您可以通过几种方式来禁止某个Pod调度到节点上。以下是一些方法&#xff1a; Node Selector&#xff1a;您可以使用Node Selector来限制Pod只能调度到带有特定标签的节点上。如果您希望完全禁止Pod调度到某些节点上&#xff0c;可以确保这些节点不拥…...

CocosCreator3.8研究笔记(七)CocosCreator 节点和组件的介绍

相信很多新手朋友&#xff0c;肯定会问&#xff0c;CocosCreator 中什么是节点&#xff1f;什么是组件&#xff1f; 一、什么是组件&#xff08;Component&#xff09;&#xff1f; Cocos Creator 3.8 的工作流程是以组件式开发为核心&#xff0c;即以组合而非继承的方式进行游…...

Ceph入门到精通-C++入门知识点

C中的双冒号(::)是作用域分解运算符&#xff08;scope resolution operator&#xff09;。 它主要有以下两种用法&#xff1a; 用于区分同名的不同成员&#xff0c;例如在不同类中声明了同名的成员函数或成员变量&#xff0c;可以使用A::B的方式来特指A类的B成员。当全局变量…...

Ansible之playbook详解和应用实例

目录 一、playbook简介 1.什么是playbook 2.playbook组成 二、应用实例 1.使用playbook安装启用httpd服务 2.使用playbook安装启用nginx服务 三、ansible-playbook其他用法 1.检查yaml文件的语法是否正确 2.检查tasks任务 3.检查指定的主机 4.指定从某个task开始运行…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...