【设计模式】Head First 设计模式——桥模式 C++实现
设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。
设计思想
桥模式。将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。
动机
某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。
桥模式能够应对这种「多维度的变化」,轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度。

- 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 输出…...
数学建模--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+前后端分离构建工程项目管理系统
工程项目管理软件(工程项目管理系统)对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营,全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…...
手把手教你搭建园林园艺小程序商城
现如今,随着互联网的快速发展,小程序成为了企业和个人展示产品和服务的新方式。在园林园艺行业,构建一个园林园艺小程序能够更好地推广和销售自己的产品和服务。那么,如何构建一个园林园艺小程序呢?下面我们来详细介绍…...
Java Iterator(迭代器)
Java迭代器(Iterator)是 Java 集合框架中的一种机制,是一种用于遍历集合(如列表、集合和映射等)的接口。 它提供了一种统一的方式来访问集合中的元素,而不需要了解底层集合的具体实现细节。 Iterator 是 …...
Logstash同步MySQL数据到ElasticSearch
当MySQL数据到一定的数量级,而且索引不能实现时,查询就会变得非常缓慢,所以使用ElasticSearch来查询数据。本篇博客介绍使用Logstash同步MySQL数据到ElasticSearch,再进行查询。 测试环境 Windows系统MySQL 5.7Logstash 7.0.1El…...
【C++】运算符重载的示例实现和应用
C运算符重载的格式: operator 运算符 比如要重载 ! 运算符 : operator ! 下面是一个例子: class DemoText{DemoText(string str, int num){m_text str; m_number num;}string m_text;int m_number; }这里来定义两个对象:…...
Kubernetes禁止调度
在Kubernetes中,您可以通过几种方式来禁止某个Pod调度到节点上。以下是一些方法: Node Selector:您可以使用Node Selector来限制Pod只能调度到带有特定标签的节点上。如果您希望完全禁止Pod调度到某些节点上,可以确保这些节点不拥…...
CocosCreator3.8研究笔记(七)CocosCreator 节点和组件的介绍
相信很多新手朋友,肯定会问,CocosCreator 中什么是节点?什么是组件? 一、什么是组件(Component)? Cocos Creator 3.8 的工作流程是以组件式开发为核心,即以组合而非继承的方式进行游…...
Ceph入门到精通-C++入门知识点
C中的双冒号(::)是作用域分解运算符(scope resolution operator)。 它主要有以下两种用法: 用于区分同名的不同成员,例如在不同类中声明了同名的成员函数或成员变量,可以使用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开始运行…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
