《设计模式的艺术》笔记 - 桥接模式
介绍
桥接模式将抽象部分与其实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式
实现
myclass.h
//
// Created by yuwp on 2024/1/12.
//#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H#include <iostream>class Implementor { // 实现抽象类,例如颜料
public:virtual void operationImpl() = 0;
};class Abstract { // 抽象类,例如毛笔
public:virtual void operation() = 0;
protected:Implementor *m_imp;
};class RefinedAbstraction : public Abstract { // 扩充抽象类,例如大号毛笔
public:RefinedAbstraction(Implementor *imp);~RefinedAbstraction();void operation() override;
};class ConcreteImplementorA : public Implementor { // 具体实现类,例如红色颜料
public:void operationImpl() override;
};#endif //DESIGNPATTERNS_MYCLASS_H
myclass.cpp
//
// Created by yuwp on 2024/1/12.
//#include "myclass.h"RefinedAbstraction::RefinedAbstraction(Implementor *imp) {m_imp = imp;
}RefinedAbstraction::~RefinedAbstraction() {}void RefinedAbstraction::operation() {if (m_imp) {m_imp->operationImpl();}std::cout << "RefinedAbstraction::operation()" << std::endl;
}void ConcreteImplementorA::operationImpl() {std::cout << "ConcreteImplementorA::operationImpl()" << std::endl;
}
main.cpp
#include <iostream>
#include <mutex>
#include "myclass.h"int main() {Implementor *imp = new ConcreteImplementorA();Abstract *ab = new RefinedAbstraction(imp);ab->operation();return 0;
}
总结
优点
1. 分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化(即抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任意组合子类,从而获得多维度组合对象)
2. 在很多情况下,桥接模式可以取代多层继承方案。多层继承方案违背了单一职责原则,复用性较差,且类的个数非常多。桥接模式是比多层继承方案更好的解决方法,它极大地减少了子类的个数。
3. 桥接模式提高了系统的可扩展性。在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合开闭原则。
缺点
1. 桥接模式的使用会增加系统的理解与设计难度。由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
2. 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。
适用场景
1. 如果一个系统需要在抽象类和具体类之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
2. 抽象部分和实现部分可以以继承的方式独立扩展而互不影响,在程序运行时可以动态地将一个抽象类子类的对象和一个实现类子类的对象进行组合,即系统需要对抽象类角色和实现类角色进行动态耦合。
3. 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
4. 对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
练习
myclass.h
//
// Created by yuwp on 2024/1/12.
//#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H#include <iostream>class FileFormat { // 实现抽象类
public:virtual void toFile(std::string data, std::string file) = 0;
};class Database { // 抽象类
public:virtual void trans() = 0;protected:FileFormat *m_fileFormat;
};class MysqlDatabase : public Database { // 扩充抽象类
public:MysqlDatabase(FileFormat *fileFormat);void trans() override;};class RedisDatabase : public Database {
public:RedisDatabase(FileFormat *fileFormat);void trans() override;protected:FileFormat *m_fileFormat;
};class TXTFileFormat : public FileFormat { // 具体实现类,例如红色颜料
public:void toFile(std::string data, std::string file) override;
};class XMLFileFormat : public FileFormat {
public:void toFile(std::string data, std::string file) override;
};class PDFFileFormat : public FileFormat {
public:void toFile(std::string data, std::string file) override;
};#endif //DESIGNPATTERNS_MYCLASS_H
myclass.cpp
//
// Created by yuwp on 2024/1/12.
//#include "myclass.h"MysqlDatabase::MysqlDatabase(FileFormat *fileFormat) {m_fileFormat = fileFormat;
}void MysqlDatabase::trans() {std::string data = "mysql";if (m_fileFormat) {m_fileFormat->toFile(data, "mysql");}
}RedisDatabase::RedisDatabase(FileFormat *fileFormat) {m_fileFormat = fileFormat;
}void RedisDatabase::trans() {std::string data = "redis";if (m_fileFormat) {m_fileFormat->toFile(data, "redis");}
}void TXTFileFormat::toFile(std::string data, std::string file) {std::cout << "\"" << data << "\"" << "转换为\"" << file << ".txt\"" << std::endl;
}void XMLFileFormat::toFile(std::string data, std::string file) {std::cout << "\"" << data << "\"" << "转换为\"" << file << ".xml\"" << std::endl;
}void PDFFileFormat::toFile(std::string data, std::string file) {std::cout << "\"" << data << "\"" << "转换为\"" << file << ".pdf\"" << std::endl;
}
main.cpp
#include <iostream>
#include <mutex>
#include "myclass.h"int main() {FileFormat *txtFormat = new TXTFileFormat();FileFormat *xmlFormat = new XMLFileFormat();FileFormat *pdfFormat = new PDFFileFormat();Database *database = new MysqlDatabase(txtFormat);database->trans();delete database;database = new MysqlDatabase(xmlFormat);database->trans();delete database;database = new MysqlDatabase(pdfFormat);database->trans();delete database;database = new RedisDatabase(txtFormat);database->trans();delete database;database = new RedisDatabase(xmlFormat);database->trans();delete database;database = new RedisDatabase(pdfFormat);database->trans();delete txtFormat;delete xmlFormat;delete pdfFormat;return 0;
}
相关文章:
《设计模式的艺术》笔记 - 桥接模式
介绍 桥接模式将抽象部分与其实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式 实现 myclass.h // // Created by yuwp on 2024/1/12. //#ifndef DESIGNPATTERNS_MYCLASS_H #define DESIGNPATTERNS_MYCLASS_H#…...
Redis高并发分布式锁
目录 场景描述 订单扣减场景举例 代码调整1 代码调整2 代码调整3 redisson锁续命核心代码 场景描述 订单扣减场景举例 //首先在redis中set stock 300 RequestMapping("/deduct_stock") public String deductStock() {int stock Integer.parseInt(stringRedi…...
组件开发遇到的问题(vue的问题)
组件的开发和引用 <template><div class"xx">组件</div> </template> <script>export default {name: viewMore,components: {},data() {return {}}} </script> <style scoped>可以定义组件都有的样式 </style> …...
vue3前端开发,感受一下组合式api和VUE2选项式的差异
vue3前端开发,感受一下组合式api和VUE2选项式的差异!今天开始,正式开始,进入学习Vue3的内容。以后代码,案例分享,都会采用组合式api的模式为大家做展示。 今天是第一节,带大家感受一下,Vue3的组…...
电梯调度问题文献阅读
电梯调度问题文献阅读 文章目录 电梯调度问题文献阅读[toc]文献阅读1. 陈纪龙,孟洪兵,吴刚等.六层电梯模拟系统的研究与实现[J].伊犁师范学院学报(自然科学版),2014,8(01):57-62.2. 陈福兰,杜虹.浅析电梯并联运行的几种调度方法[J].装备制造技术,2012,(10):178-180190.3. 马春江…...
文心一言 VS 讯飞星火 VS chatgpt (183)-- 算法导论13.4 7题
七、用go语言,假设用 RB-INSERT 将一个结点 x 插入一棵红黑树,紧接着又用 RB-DELETE 将它从树中删除。结果的红黑树与初始的红黑树是否一样?证明你的答案。 文心一言: 首先,我们需要明确RB-INSERT和RB-DELETE的基本操…...
ChatGLM vs ChatGPT
所有的NLP大模型 都是transformer结构 1.Mask attention 的策略不同 2.训练任务目标不同 国内大模型nb公司:百度、清华智谱 一、主流大模型 粉色:Encoder-only。 绿色:Encoder-Decoder,尽头智谱ChatGLM。 蓝色:…...
leetcode热题100.三数之和
Problem: 15. 三数之和 文章目录 题目解题方法复杂度Code 题目 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元…...
GitLab服务器忘记root密码处理方式
GitLab服务器忘记root密码处理方式 文章目录 GitLab服务器忘记root密码处理方式1. Gitlab查看用户id号1. 通过api接口查询2. 在Linux终端里直接通过curl命令查询 2. 进入GitLab数据库中查询并修改root密码 1. Gitlab查看用户id号 1. 通过api接口查询 接口查询地址:…...
js-cookie的使用--token的数据实现持久化
1.下载 npm install js-cookie 2.引入 import Cookies from "js-cookie"; 3.使用 // 写入cookie Cookies.set(name, value) // 读取 Cookies.get(name) // > value Cookies.get(nothing) // > undefined // 读取所有可见的cookie Cookies.get() // 删除某项co…...
【实战】SpringBoot自定义 starter及使用
文章目录 前言技术积累SpringBoot starter简介starter的开发步骤 实战演示自定义starter的使用写在最后 前言 各位大佬在使用springboot或者springcloud的时候都会根据需求引入各种starter,比如gateway、feign、web、test等等的插件。当然,在实际的业务…...
网络爬虫采集工具
在当今数字化的时代,获取海量数据对于企业、学术界和个人都至关重要。网络爬虫成为一种强大的工具,能够从互联网上抓取并提取所需的信息。本文将专心分享关于网络爬虫采集数据的全面指南,深入探讨其原理、应用场景以及使用过程中可能遇到的挑…...
【协议】XMLHttpRequest的梳理和总结
1. 前言 本篇梳理和总结一下XMLHttpRequest。 2. XMLHttpRequest原型对象的属性和方法 属性和方法说明示例new XMLHttpRequest() 功能:创建XHR对象 输入: 输出:XHR实例化对象 <略> XMLHttpRequest.prototype .open(method, url, asyn…...
AI教我学编程之C#类的基本概念(1)
前言 在AI教我学编程之C#类型 中,我们学习了C#类型的的基础知识,而类正是类型的一种. 目录 区分类和类型 什么是类? 对话AI 追问 实操 追踪属性的使用 AI登场 逐步推进 提出疑问 药不能停 终于实现 探索事件的使用 异步/交互操作 耗时操…...
前端js 数据结构:对象 object、数组Array 、Map 的创建、增删改 / 遍历数据
目录 前端js 数据结构:对象、数组、Map 的使用1 对象(object)1.1 创建对象1.1.1 对象字面量(最常用): {}1.1.2 使用 new 关键字和对象构造函数1.1.3 Object.create() 1.2 修改对象1.2.1 直接赋值:对象的属性名直接赋值1.2.2 点号/…...
ARM_Linux的NFS网络文件系统的搭建
介绍: NFS是network filesystem的简称,可以不同的主机通过网络访问远端的NFS服务器共享出来的文件,这样主机通过网络访问NFS服务器,我们就可以在开发板上通过网络访问主机的文件。 为什么要使用NFS网络文件呐? 1、传…...
vscode配置web开发环境(WampServer)
这里直接去下载了集成的服务器组件wampserver,集成了php,MySQL,Apache 可能会出现安装问题,这里说只有图上这些VC包都安装了才能继续安装,进入报错里提供的链接 在页面内搜索相关信息 github上不去可以去镜像站 下载…...
00-Rust前言
问:为什么要近期想学习Rust? 答: Rust出来也是有一段时间了,从Microsoft吵着要重构他们的C"祖传代码"开始,Rust就披着“高效,安全”的头衔。而自己决定要学习Rust,是因为近期发现:涉…...
3.conda的使用
anaconda安装 ubuntu 安装conda 系统架构 uname -m打开终端,不启动base conda config --set auto_activate_base falseconda命令使用 1.查看conda版本 conda --version2.查看conda配置环境 conda config --show3.设置镜像 #设置清华镜像 conda config --add…...
IPv6自动隧道---6to4中继
6to4中继 普通IPv6网络需要与6to4网络通过IPv4网络互通,这可以通过6to4中继路由器方式实现。所谓6to4中继,就是通过6to4隧道转发的IPv6报文的目的地址不是6to4地址,但转发的下一跳是6to4地址,该下一跳为路由器我们称之为6to4中继。隧道的IPv4目的地址依然从下一跳的6to4地…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
