【设计模式】深入理解Python中的桥接模式(Bridge Pattern)
深入理解Python中的桥接模式(Bridge Pattern)
在软件开发中,我们常常会遇到一个类随着功能的扩展,继承层次越来越复杂,导致系统僵化,难以维护。桥接模式(Bridge Pattern)提供了一种优雅的方式,通过分离抽象部分和实现部分,降低类的复杂性,使得系统具有更好的扩展性和灵活性。
本文将详细介绍桥接模式的原理、适用场景、如何在Python中实现它,以及一些常见的优化方式。
1. 什么是桥接模式?
桥接模式是一种结构型设计模式,旨在将抽象部分与它的实现部分分离,使它们可以独立地进行变化。简单来说,桥接模式通过创建独立的抽象层和实现层,让它们分别可以独立扩展,不互相影响。
这种模式的关键在于将一个大类拆分成多个更小的类,并通过“桥接”让这些类协同工作,从而减少子类的数量并避免层次过于复杂。
桥接模式的结构
桥接模式包含两个主要部分:
- 抽象部分(Abstraction):定义了高层的操作接口,内部持有对实现部分(Implementor)的引用。
- 实现部分(Implementor):定义底层实现接口,提供抽象部分依赖的实际功能。
通过桥接模式,可以将抽象和实现分离,使得它们可以独立扩展和演化。
UML类图表示
+------------------+ +-------------------+
| Abstraction | | Implementor |
+------------------+ +-------------------+
| - implementor | | +operation_impl() |
| +operation() | +-------------------+
+------------------+ ▲▲ || || |
+------------------+ +-------------------+
| RefinedAbstraction| | ConcreteImplementor|
+------------------+ +-------------------+
| +operation() | | +operation_impl() |
+------------------+ +-------------------+
- Abstraction:定义抽象操作接口,内部引用
Implementor接口。 - Refined Abstraction:扩展了
Abstraction的具体操作实现。 - Implementor:定义底层操作接口,通常有多个不同的实现类。
- ConcreteImplementor:具体实现
Implementor接口,提供实际的业务逻辑。
2. 桥接模式的应用场景
桥接模式在以下场景非常有用:
- 避免类爆炸:当类的属性和行为多种组合时,通过继承会导致子类过多,桥接模式可以减少类的数量。
- 多维度变化的系统:当一个系统可能存在多个维度的变化(如操作系统平台和UI风格),桥接模式可以将这些变化独立出来,并允许它们自由组合。
- 分离抽象和实现:在需要抽象和实现解耦的系统中,桥接模式提供了一种优雅的方式来降低系统耦合度。
典型应用场景
- 跨平台GUI工具:UI控件可能需要支持多个平台(如Windows、Linux、macOS),同时还可能有不同的样式和行为。桥接模式可以将平台依赖和控件行为分开实现。
- 文件系统操作:文件系统的抽象和具体操作方式(如不同操作系统下的文件系统实现)可以通过桥接模式分离,使得系统支持多种文件操作方式。
3. Python 实现桥接模式
3.1 定义实现者接口(Implementor)
首先,我们定义一个 Implementor 接口,它代表系统的实际功能实现部分。在本例中,假设我们要实现不同的绘图工具(比如画笔、喷枪),每个工具的操作不同,但它们都有一个绘制功能。
from abc import ABC, abstractmethod# 实现者接口
class DrawingImplementor(ABC):@abstractmethoddef draw_shape(self, shape: str):pass
3.2 实现具体实现者(Concrete Implementor)
接下来,定义两个具体的实现者,一个是使用画笔绘图,另一个是使用喷枪绘图。
# 具体实现者:画笔
class Pen(DrawingImplementor):def draw_shape(self, shape: str):return f"Drawing {shape} with a Pen."# 具体实现者:喷枪
class SprayGun(DrawingImplementor):def draw_shape(self, shape: str):return f"Drawing {shape} with a Spray Gun."
3.3 定义抽象类(Abstraction)
Abstraction 定义了系统的高层操作接口,持有 Implementor 的引用,客户端可以通过该接口调用底层的实现逻辑。
# 抽象类
class Shape(ABC):def __init__(self, implementor: DrawingImplementor):self.implementor = implementor@abstractmethoddef draw(self):pass
3.4 实现具体抽象类(Refined Abstraction)
我们需要定义具体的形状类,它们继承 Shape,并调用 Implementor 进行具体的绘图操作。比如,我们可以定义 Circle 和 Square 两个形状,它们可以使用不同的工具来绘制。
# 具体的抽象类:圆形
class Circle(Shape):def draw(self):return self.implementor.draw_shape("Circle")# 具体的抽象类:正方形
class Square(Shape):def draw(self):return self.implementor.draw_shape("Square")
3.5 客户端代码
客户端通过创建具体的抽象类,并传入不同的实现者,来进行具体的操作。可以通过桥接模式轻松切换实现者,而不需要修改高层逻辑。
# 测试桥接模式
pen = Pen()
spray_gun = SprayGun()circle_with_pen = Circle(pen)
print(circle_with_pen.draw()) # 使用画笔画圆形square_with_spray_gun = Square(spray_gun)
print(square_with_spray_gun.draw()) # 使用喷枪画正方形
输出结果:
Drawing Circle with a Pen.
Drawing Square with a Spray Gun.
通过这个例子,我们可以看到,Circle 和 Square 形状的高层逻辑与具体的绘制工具解耦,绘制工具可以根据需要灵活切换而不影响其他代码。
4. 桥接模式的优缺点
优点
- 分离抽象和实现:桥接模式将抽象层和实现层分离,降低了代码耦合度,增强了系统的可扩展性。
- 提高系统的可维护性:通过减少子类的数量,桥接模式避免了复杂的继承结构,使得系统更加易于维护。
- 扩展性强:抽象部分和实现部分都可以独立扩展,不会相互影响。新增抽象类或实现类时不需要修改已有代码,符合开闭原则。
缺点
- 增加复杂性:虽然桥接模式降低了子类的数量,但它引入了更多的接口和类,可能会增加系统的复杂度,特别是当系统规模较小时,过度设计反而使代码难以理解。
- 难以理解:对于初学者来说,桥接模式可能不容易理解,特别是分离抽象和实现的概念在某些简单场景中显得多余。
5. 改进桥接模式:使用Python的动态特性
在Python中,由于其动态特性,我们可以进一步简化桥接模式的实现。例如,直接将实现逻辑作为参数传递给抽象类,而无需定义严格的接口,这可以减少代码的冗余。
动态实现示例
class Shape:def __init__(self, drawing_tool):self.drawing_tool = drawing_tooldef draw(self, shape: str):return self.drawing_tool(shape)# 使用画笔绘制
def draw_with_pen(shape):return f"Drawing {shape} with a Pen."# 使用喷枪绘制
def draw_with_spray_gun(shape):return f"Drawing {shape} with a Spray Gun."# 测试动态桥接
circle = Shape(draw_with_pen)
print(circle.draw("Circle"))square = Shape(draw_with_spray_gun)
print(square.draw("Square"))
输出结果与之前相同,但我们通过Python的动态特性简化了代码结构,不需要显式定义实现者接口。
这个改进版本适用于较为简单的场景。
6. 结论
桥接模式是一种非常强大的设计模式,尤其适合在多维度变化的系统中应用。它通过分离抽象和实现,降低了代码的耦合度,增强了系统的扩展性和维护性。在Python中,桥接模式不仅能帮助我们避免复杂的继承结构,还能通过语言的动态特性进行简化,使得代码更加灵活。
在本文中,我们讨论了桥接模式的核心概念、适用场景、详细的Python实现以及优化方式,希望你在未来的项目中能够灵活运用这一模式。
相关文章:
【设计模式】深入理解Python中的桥接模式(Bridge Pattern)
深入理解Python中的桥接模式(Bridge Pattern) 在软件开发中,我们常常会遇到一个类随着功能的扩展,继承层次越来越复杂,导致系统僵化,难以维护。桥接模式(Bridge Pattern)提供了一种…...
YOLOv11改进策略【卷积层】| SAConv 可切换的空洞卷积 二次创新C3k2
一、本文介绍 本文记录的是利用SAConv优化YOLOv11的目标检测网络模型。空洞卷积是一种在不增加参数量和计算量的情况下,通过在卷积核元素之间插入空洞来扩大滤波器视野的技术。并且为了使模型能够适应不同尺度的目标,本文利用SAConv将不同空洞率卷积结果进行结合,来获取更全…...
Javaweb基础-axios
Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。 GET方法 get请求第一种写法 //后端 Slf4j RestController RequestMapping("/demo") public class DemoController {RequestMapping("/getTest")// 被RequestParam标记的参数…...
智能EDA小白从0开始 —— DAY20 OrCAD
以下是对OrCAD和MATLAB两种EDA工具的深入解析,内容扩展至约2220字: OrCAD:电子设计自动化的强大工具 OrCAD,作为电子设计自动化(EDA)领域的佼佼者,为电子工程师们提供了一套全面的设计解决方案…...
C# WebApi 接口测试工具:WebApiTestClient应用技术详解
目录 一、引言 二、WebApiTestClient介绍 1、特性 2、应用场景 三、WebApiTestClient具体使用 1、WebApi项目引入组件 2、如何使用组件 1、修改Api.cshtml文件 2、配置读取注释的xml路径 3、测试接口 四、总结 一、引言 由于最近项目需要开发WebApi接口&…...
Qt_ymode自己实现
文章内容: 通过Qt实现Ymode协议的封装。通过传入的数据从里面一包一包拿数据。可以用作平时串口和网口的通信。也可以用来程序升级。 #include "ymodem.h"Ymodem::Ymodem() {m_data = nullptr; }Ymodem...
5.3章节python中字典:字典创建、元素访问、相关操作
1.字典的创建和删除 2.字典的访问和遍历 3.字典的相关操作 4.字典的生成式 一、字典的创建和删除 字典(dictionary)是一种用于存储键值对(key-value pairs)的数据结构。每个键(key)都映射到一个值…...
ECCV2024 Tracking 汇总
一、OneTrack: Demystifying the Conflict Between Detection and Tracking in End-to-End 3D Trackers paper: https://www.ecva.net/papers/eccv_2024/papers_ECCV/papers/01174.pdf 二、VETRA: A Dataset for Vehicle Tracking in Aerial Imagery paper&#…...
C语言知识点
命名规则: 字符组成:标识符只能由字母(A~Z,a~z)、数字(0~9)和下划线(_)组成。首字符要求:标识符的第一个字符必须是字母或下划线,不能是数字。长…...
ICMP协议以及ARP欺骗攻击
ping 命令使用的是 ICMP(Internet Control Message Protocol)协议,而不是 TCP 或 UDP 协议。因此,ping 命令并不使用特定的端口号。 ICMP 协议 ICMP 是一种网络层协议,主要用于在 IP 网络中传递控制消息。ping 命令利…...
qt5.12.12插件机制无法加载插件问题
环境:win11 vs2015 qt5.12.12 问题描述:确保插件代码正确的情况下,无法解析插件接口(即QPluginLoader类的instance(); 返回为空)。 问题现象:1、qt5.12.12的debug下无法解析;2、release下禁…...
机器学习面试笔试知识点-线性回归、逻辑回归(Logistics Regression)和支持向量机(SVM)
机器学习面试笔试知识点-线性回归、逻辑回归Logistics Regression和支持向量机SVM 一、线性回归1.线性回归的假设函数2.线性回归的损失函数(Loss Function)两者区别3.简述岭回归与Lasso回归以及使用场景4.什么场景下用L1、L2正则化5.什么是ElasticNet回归6.ElasticNet回归的使…...
SpringBoot民宿预订系统设计与实现
2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…...
linux环境下C程序的编译过程以及makefile的简单使用
在windows下,很多用来进行编程软件对于写好的文件,点击编译即可生成想要文件。如.exe可执行文件,.hex文件或者.bin文件等等。软件为我们省略了很多事。但是对于linux初学者来说,初次接触linux系统,面对命令行黑框框有点…...
【从零开始的LeetCode-算法】945. 使数组唯一的最小增量
给你一个整数数组 nums 。每次 move 操作将会选择任意一个满足 0 < i < nums.length 的下标 i,并将 nums[i] 递增 1。 返回使 nums 中的每个值都变成唯一的所需要的最少操作次数。 生成的测试用例保证答案在 32 位整数范围内。 示例 1: 输入&am…...
Java程序设计:spring boot(2)
目录 1 Spring MVC 零配置创建与部署 1.1 创建Spring MVC Web⼯程 1.2 pom.xml 添加坐标相关配置 1.3 添加源代码 1.4 添加视图 1.5 SpringMVC 配置类添加 1.6 入口文件代码添加 1.7 部署与测试 2 Spring Boot 概念&特点 2.1 框架概念 2.2 框架特点 2.3 Spring…...
服务器运维监控平台
云监控平台-简介 一:简介 “phoenix” 是一个灵活可配置的开源监控平台,主要用于监控应用程序、服务器、docker、数据库、网络、tcp 端口和 http 接口,通过实时收集、汇聚和分析监控信息,实现在发现异常时立刻推送告警信息&…...
css中 global 和 deep(两个样式穿透) 区别
1.:global(selector):这个伪类选择器会选择所有全局的、未被其他样式表覆盖的元素。换句话说,它会匹配所有没有被其他样式表(例如内联样式或外部样式表)所影响的元素。 :global(p) {color: red; }这段代码会将所有 <p> 元素…...
【星闪技术】WS63E模块的WiFi客户端测试
引言 我所计划的WS63E测试要实现MQTT联网,所以首先需要确保开发板连接WiFi。今天来测试一下WiFi功能。 程序分析 WiFi客户端的例子在src/application/samples/wifi/sta_sample目录下。这个例子看上去和hi3861的例子差不多。 这段程序是一个用于嵌入式设备的Wi-F…...
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点 面试题目1:Kotlin中的协程与线程的区别是什么?如何在Android中使用协程进行异步编程? 解答: 协…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
