设计模式之Bridge模式的C++实现
目录
1、Bridge模式的提出
2、Bridge模式的定义
3、Bridge模式总结
4、需求描述
5、多继承方式实现
6、使用Bridge设计模式实现
1、Bridge模式的提出
在软件功能模块设计中,如果类的实现功能划分不清晰,使得继承得到的子类往往是随着需求的变化,子类急剧膨胀,充斥重复代码。将类要实现功能划分清楚是设计较好软件框架的关键。
2、Bridge模式的定义
对于类的实现功能具有两个变化的维度,甚至由多个维度的变化,使用类的多继承实现方式,会使子类数目急剧膨胀。Bridge模式使用“对象间的组合关系”解耦抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度变化,即将不同的维度分别进行抽象,然后各自根据变化维度进行继承。
3、Bridge模式总结
Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类甚至有多个变化的维度,这时使用Bridge模式的扩展模式来设计代码。
4、需求描述
手机有固有属性(材料、颜色、摄像头个数)和软件属性(开机动画、网络打印、支持app数目)。有2款A、B类型手机,A、B分别继承手机的固有属性功能。在A款基础上又有2款Higher、Pro类型,Higher、Pro分别继承手机的软件功能;在B款的基础上也有2种Higher、Pro,这2种也分别继承手机的软件功能。
5、多继承方式实现
#include <iostream>class MobilePhone
{
public://手机材质virtual void PhoneMaterial()=0;//手机颜色virtual void PhoneColor()=0;//手机大小virtual void PhoneCameNum()=0;//开机动画virtual void BootAnimation()=0;//网络打印类型virtual void NetPrintType()=0;//软件支持数目virtual void SoftSuppotNum()=0;virtual ~MobilePhone(){};};//下面的类继承关系中,不同层级的类继承不同抽象函数,可以分函数抽象一个类,见Bridge模式。class APhoneNoraml:public MobilePhone
{
public:virtual ~APhoneNoraml(){};virtual void PhoneMaterial()override{std::cout << "Glass material" << std::endl;};virtual void PhoneColor()override{std::cout << "2 Colors" << std::endl;};virtual void PhoneCameNum()override{std::cout << "2 CamNum" << std::endl;};
};class BPhoneNoraml:public MobilePhone
{
public:virtual ~BPhoneNoraml(){};virtual void PhoneMaterial()override{std::cout << "Glass material" << std::endl;};virtual void PhoneColor()override{std::cout << "3 Colors" << std::endl;};virtual void PhoneCameNum()override{std::cout << "3 CamNum" << std::endl;};
};class APhoneHiger:public APhoneNoraml
{
public:virtual ~APhoneHiger(){};virtual void BootAnimation()override{APhoneNoraml::PhoneMaterial();APhoneNoraml::PhoneColor();APhoneNoraml::PhoneCameNum();std::cout << "good luck" << std::endl;};virtual void NetPrintType()override{std::cout << "Support base txt type" << std::endl;};virtual void SoftSuppotNum()override{std::cout << "Support 20 app" << std::endl;};
};class BPhoneHiger:public BPhoneNoraml
{
public:virtual ~BPhoneHiger(){};virtual void BootAnimation()override{BPhoneNoraml::PhoneMaterial();BPhoneNoraml::PhoneColor();BPhoneNoraml::PhoneCameNum();std::cout << "gook lunck" << std::endl;};virtual void NetPrintType()override{std::cout << "Support base txt type" << std::endl;};virtual void SoftSuppotNum()override{std::cout << "Support 20 app" << std::endl;};};class APhonePro:public APhoneNoraml
{
public:virtual ~APhonePro(){};virtual void BootAnimation()override{APhoneNoraml::PhoneMaterial();APhoneNoraml::PhoneColor();APhoneNoraml::PhoneCameNum();std::cout << "best wishes" << std::endl;};virtual void NetPrintType()override{std::cout << "Support base 3 type" << std::endl;};virtual void SoftSuppotNum()override{std::cout << "Support 30 app" << std::endl;};
};class BPhonePro:public BPhoneNoraml
{
public:virtual ~BPhonePro(){};virtual void BootAnimation()override{BPhoneNoraml::PhoneMaterial();BPhoneNoraml::PhoneColor();BPhoneNoraml::PhoneCameNum();std::cout << "best wishes" << std::endl;};virtual void NetPrintType()override{std::cout << "Support base 3 type" << std::endl;};virtual void SoftSuppotNum()override{std::cout << "Support 30 app" << std::endl;};};int main()
{MobilePhone* higherA = new APhoneHiger();higherA->BootAnimation();higherA->NetPrintType();higherA->SoftSuppotNum();delete higherA;higherA = nullptr;MobilePhone* proA = new APhonePro();proA->BootAnimation();proA->NetPrintType();proA->SoftSuppotNum();delete proA;proA = nullptr;return 0;
}
运行结果如下:

6、使用Bridge设计模式实现
#include <iostream>//将第一个变化维度的三个函数抽象成一个类,供第二层继承使用
class MobilePhone
{
public://手机材质virtual void PhoneMaterial()=0;//手机颜色virtual void PhoneColor()=0;//手机大小virtual void PhoneCameNum()=0;virtual ~MobilePhone(){}
};//将第二个变化维度的三个函数抽象出一个类,供第三层继承使用
class MobileSoft
{
public:MobileSoft(MobilePhone* p):Imp(p){};MobilePhone *Imp;//开机动画virtual void BootAnimation()=0;//网络打印类型virtual void NetPrintType()=0;//软件支持数目virtual void SoftSuppotNum()=0;
};class APhoneNoraml:public MobilePhone
{
public:virtual ~APhoneNoraml(){};virtual void PhoneMaterial()override{std::cout << "Glass material" << std::endl;};virtual void PhoneColor()override{std::cout << "2 Colors" << std::endl;};virtual void PhoneCameNum()override{std::cout << "2 CamNum" << std::endl;};
};class BPhoneNoraml:public MobilePhone
{
public:virtual ~BPhoneNoraml(){};virtual void PhoneMaterial()override{std::cout << "Glass material" << std::endl;};virtual void PhoneColor()override{std::cout << "3 Colors" << std::endl;};virtual void PhoneCameNum()override{std::cout << "3 CamNum" << std::endl;};
};//在第三层继承关系处使用对象组合。
class PhoneHiger:public MobileSoft
{
public:PhoneHiger(MobilePhone *p):MobileSoft(p){};virtual ~PhoneHiger(){};virtual void BootAnimation()override{Imp->PhoneMaterial();Imp->PhoneColor();Imp->PhoneCameNum();std::cout << "good luck" << std::endl;};virtual void NetPrintType()override{std::cout << "Support base txt type" << std::endl;};virtual void SoftSuppotNum()override{std::cout << "Support 20 app" << std::endl;};
};class PhonePro:public MobileSoft
{
public:PhonePro(MobilePhone *p):MobileSoft(p){};virtual ~PhonePro(){};virtual void BootAnimation()override{Imp->PhoneMaterial();Imp->PhoneColor();Imp->PhoneCameNum();std::cout << "best wishes" << std::endl;};virtual void NetPrintType()override{std::cout << "Support base 3 type" << std::endl;};virtual void SoftSuppotNum()override{std::cout << "Support 30 app" << std::endl;};
};int main()
{std::cout << " ************** PhoneHiger ************** " << std::endl;MobilePhone *normalA = new APhoneNoraml();MobileSoft *higherA = new PhoneHiger(normalA);higherA->BootAnimation();higherA->NetPrintType();higherA->SoftSuppotNum();std::cout << "\n ************** PhonePro ************** " << std::endl;MobilePhone *normalPro = new APhoneNoraml();MobileSoft *proA = new PhonePro(normalPro);proA->BootAnimation();proA->NetPrintType();proA->SoftSuppotNum();return 0;
}
运行结果如下:

上面的代码将不同的变化维度分别抽象成一个类,供子类继承;并且其中一个维度的继承关系用“类成员是基类对象”组合的方式进行替代,使功能类代码具有良好的扩展性,也遵循单一职责原则。
相关文章:
设计模式之Bridge模式的C++实现
目录 1、Bridge模式的提出 2、Bridge模式的定义 3、Bridge模式总结 4、需求描述 5、多继承方式实现 6、使用Bridge设计模式实现 1、Bridge模式的提出 在软件功能模块设计中,如果类的实现功能划分不清晰,使得继承得到的子类往往是随着需求的变化&am…...
springboot异步任务
在Service类声明一个注解Async作为异步方法的标识 package com.qf.sping09test.service;import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service;Service public class AsyncService {//告诉spring这是一个异步的方法Asyncp…...
Flutter父宽度自适应子控件的宽度
需求: 控件随着金币进行自适应宽度 image.png 步骤: 1、Container不设置宽度,需要设置约束padding; 2、文本使用Flexible形式; Container(height: 24.dp,padding: EdgeInsetsDirectional.only(start: 8.dp, end: 5.d…...
什么是 API 安全?学习如何防止攻击和保护数据
随着 API 技术的普及,API 安全成为了一个越来越重要的问题。本文将介绍什么是 API 安全,以及目前 API 面临的安全问题和相应的解决方案。 什么是 API 安全 API 安全是指保护 API 免受恶意攻击和滥用的安全措施。API 安全通常包括以下几个方面࿱…...
简述 TCP 和 UDP 的区别以及优缺点和使用场景?
一、TCP与UDP区别总结: 1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接 2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失&…...
react进阶
react-virtualized的高阶组件,Autosize可以使屏幕适配。使用render-props模式来获取到AutoSizer组件暴露的width和height属性。JSON.parse(JSON.stringify())不适用于有undefined的数据。 深拷贝的使用,不能使用在有undefined的数据中。有直接过滤undefi…...
使用windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】
文章目录 1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透,将WebDav服务暴露在公网3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访问测试 4. 安装Raidrive客户端4.1 连接WebDav服务器4.2 连接成功4.2 连接成功 1. Linux(centos8…...
科技感响应式管理系统后台登录页ui设计html模板
做了一个科技感的后台管理系统登录页设计,并且尝试用响应式布局把前端html写了出来,发现并没有现象中的那么容易,chrome等标准浏览器都显示的挺好,但IE11下面却出现了很多错位,兼容起来还是挺费劲的,真心不…...
Lombok的使用及注解含义
文章目录 一、简介二、如何使用2.1、在IDEA中安装Lombok插件2.2、添加maven依赖 三、常用注解3.1、Getter / Setter3.2、ToString3.3、NoArgsConstructor / AllArgsConstructor3.4、EqualsAndHashCode3.5、Data3.6、Value3.7、Accessors3.7.1、Accessors(chain true)3.7.2、Ac…...
实时通信应用的开发:Vue.js、Spring Boot 和 WebSocket 整合实践
目录 1. 什么是webSocket 2. webSocket可以用来做什么? 3. webSocket协议 4. 服务器端 5. 客户端 6. 测试通讯 1. 什么是webSocket WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务…...
【C++】C++异常
文章目录 1. C语言传统处理错误的方式2. C异常的概念3. 异常的使用3.1 异常的抛出和捕获3.2 异常的重新抛出3.3 异常安全3.4 异常规范 4. C标准库的异常体系5. 自定义的异常体系6. 异常的优缺点 1. C语言传统处理错误的方式 C语言传统的错误处理机制有两个: 终止程…...
学生成绩管理系统V2.0
某班有最多不超过30人(具体人数由键盘输入)参加某门课程的考试,参考前面章节的“学生成绩管理系统V1.0”,用一维数组和函数指针作函数参数编程实现如下菜单驱动的学生成绩管理系统,其中每位同学的学号和成绩等数据可以…...
【C++】开源:tinyxml2解析库配置使用
😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍tinyxml2解析库配置使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,…...
如何使用webpack打包一个库library,使用webpack打包sdk.
如何使用webpack打包一个库library 如果你需要自己封装一些包给别人使用,那么可以参考以下方法 初始化库 mkdir library cd library npm init -y经过以上步骤后会生成一个library文件夹,里面包含一个package.json文件。然后简单修改为如下所示: {&qu…...
项目一:基于stm32的阿里云智慧消防监控系统
若该文为原创文章,转载请注明原文出处。 Hi,大家好,我是忆枫,今天向大家介绍一个单片机项目。 一、简介 智慧消防监控系统,是用于检测火灾,温度,烟雾的监控系统。以 stm32单片机为核心外加 MQ…...
【果树农药喷洒机器人】Part6:基于深度相机与分割掩膜的果树冠层体积探测方法
📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...
打印1到最大的n位数
目录 1.题目概述 2.题解 1.题目概述 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。 1. 用返回一个整数列表来代替打印 2. n 为正整数,0 < n < 5 示例: 输入…...
设计模式行为型——状态模式
目录 状态模式的定义 状态模式的实现 状态模式角色 状态模式类图 状态模式举例 状态模式代码实现 状态模式的特点 优点 缺点 使用场景 注意事项 实际应用 在软件开发过程中,应用程序中的部分对象可能会根据不同的情况做出不同的行为,把这种对…...
ElastAlert通过飞书机器人发送报警通知
前言 公司采用ELK架构搜集业务系统的运行日志,以前开发人员只有在业务出现问题的时候,才会去kibana上进行日志搜索操作,每次都是被用户告知系统出问题了,这简直是被啪啪打脸~ 于是痛定思痛,决定主动出击,…...
恒温碗语音芯片,具备数码管驱动与温度传感算法,WT2003H-B012
近年来,随着科技的飞速发展,智能家居产品已然成为了现代生活的一部分,为人们的生活带来了更多的便利和舒适。在这个不断演进的领域中,恒温碗多功能语音芯片——WT2003H-B012成为众多厂商的首选,为智能家居领域注入了全…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
