Java二十三种设计模式-桥接模式(10/23)
桥接模式:解耦抽象与实现的灵活设计
引言
桥接模式(Bridge Pattern)是一种结构型设计模式,用于将抽象部分与其实现部分分离,使它们可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(interface)模式。
基础知识,java设计模式总体来说设计模式分为三大类:
(1)创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
(2)结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
(3)行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
第一部分:桥接模式概述
1.1 定义与用途
桥接模式的基本定义
桥接模式(Bridge Pattern)是一种结构型设计模式,其核心思想是将类的抽象部分与它的实现部分分离,使它们可以独立地变化。这种模式允许系统在不修改原有抽象层代码的情况下,通过更换实现层来扩展系统的功能。
解释为何需要桥接模式
- 解耦抽象与实现:在软件开发中,经常会遇到抽象和实现紧密耦合的情况,这限制了系统的灵活性和可扩展性。桥接模式通过将它们分离,提高了系统的灵活性。
- 扩展系统功能:使用桥接模式,可以在不修改原有抽象类代码的情况下,通过增加新的实现类来扩展系统的功能。
- 避免多重继承:在不支持多重继承的语言中,桥接模式提供了一种替代方案,允许一个类同时具备多个接口的特征。
1.2 桥接模式的组成
抽象化(Abstraction)
- 定义:定义了抽象类的接口,规定了可以关联的具体实现化角色。
- 角色:作为桥接模式的基础,抽象化角色将业务逻辑与实现细节分离。
抽象化实现(Refined Abstraction)
- 定义:扩展抽象化角色,添加了对具体实现化对象的引用,并实现更具体的业务逻辑。
- 角色:具体抽象化角色提供了与抽象化角色一致或更丰富的接口,并委托具体实现化角色来完成某些操作。
实现化(Implementor)
- 定义:定义了实现化角色的接口,它规定了实现化对象必须实现的接口。
- 角色:实现化角色是桥接模式中的具体实现部分,它独立于抽象化角色变化。
具体实现化(Concrete Implementor)
- 定义:实现了实现化角色的接口,提供了具体的实现细节。
- 角色:具体实现化角色是实现化角色的具体实现,它定义了实现化接口的具体行为。
客户端(Client)
- 角色:使用抽象化角色来完成业务逻辑,并通过抽象化角色与实现化角色交互。
桥接模式通过这种角色分离,使得抽象部分和实现部分可以独立地变化,从而提高了系统的灵活性和可扩展性。在下一部分中,我们将通过Java代码示例来展示桥接模式的具体实现。
第二部分:桥接模式的实现
2.1 Java实现示例
以下是使用Java语言实现桥接模式的代码示例。假设我们有一个图形接口,它有不同的实现方式,如圆形和矩形,并且每种图形都有多种绘制方式,如实线和虚线。
// 实现化接口
interface DrawingAPI {void draw();
}// 具体实现化:实线图形
class SolidDrawingAPI implements DrawingAPI {@Overridepublic void draw() {System.out.println("Drawing with solid lines.");}
}// 具体实现化:虚线图形
class DashedDrawingAPI implements DrawingAPI {@Overridepublic void draw() {System.out.println("Drawing with dashed lines.");}
}// 抽象化角色
abstract class Shape {protected DrawingAPI drawingAPI;public Shape(DrawingAPI drawingAPI) {this.drawingAPI = drawingAPI;}abstract void draw();
}// 具体抽象化:圆形
class Circle extends Shape {private float radius;public Circle(DrawingAPI drawingAPI, float radius) {super(drawingAPI);this.radius = radius;}@Overridevoid draw() {drawingAPI.draw();System.out.println("Drawing a circle with radius " + radius);}
}// 具体抽象化:矩形
class Rectangle extends Shape {private float width;private float height;public Rectangle(DrawingAPI drawingAPI, float width, float height) {super(drawingAPI);this.width = width;this.height = height;}@Overridevoid draw() {drawingAPI.draw();System.out.println("Drawing a rectangle with width " + width + " and height " + height);}
}// 客户端代码
public class Client {public static void main(String[] args) {DrawingAPI solidAPI = new SolidDrawingAPI();DrawingAPI dashedAPI = new DashedDrawingAPI();Shape circle = new Circle(solidAPI, 5.0f);circle.draw();Shape rectangle = new Rectangle(dashedAPI, 4.0f, 6.0f);rectangle.draw();}
}
2.2 桥接模式中的角色和职责
抽象化(Abstraction)
- 职责:定义了与实现化角色之间的接口,不涉及具体的实现细节。
抽象化实现(Refined Abstraction)
- 职责:扩展抽象化角色,实现更具体的业务逻辑,并使用实现化角色来完成某些操作。
实现化(Implementor)
- 职责:定义了实现化角色的接口,提供了一个或多个方法供抽象化角色调用。
具体实现化(Concrete Implementor)
- 职责:实现了实现化接口的具体类,提供了实现化接口的具体实现。
相互作用
- 抽象化与实现化:抽象化角色通过组合实现化角色来实现自己的部分行为。
- 具体抽象化与具体实现化:具体抽象化角色通过组合具体实现化角色来完成具体的行为。
桥接模式通过将抽象部分与实现部分分离,允许它们独立地扩展和变化。这种模式提高了系统的灵活性和可扩展性,使得在不修改原有代码的情况下,可以通过增加新的实现类来扩展系统的功能。在下一部分中,我们将探讨桥接模式的使用场景。
第三部分:桥接模式的使用场景
3.1 系统需要独立变化的两个维度
在软件设计中,经常会遇到需要从两个或多个维度进行扩展的情况。例如,一个图形界面库可能需要支持不同类型的图形(如圆形、矩形等)以及不同的绘制样式(如实线、虚线等)。每个维度都可能独立变化,增加新的图形类型或绘制样式。
桥接模式的应用:
- 独立变化:桥接模式允许抽象部分(如图形类型)和实现部分(如绘制样式)独立变化,互不影响。
- 扩展性:当需要添加新的图形类型或绘制样式时,只需添加相应的具体抽象化角色或具体实现化角色,无需修改现有代码。
- 灵活性:客户端代码通过抽象化角色与系统交互,不同的抽象化角色可以绑定不同的实现化角色,提供了高度的灵活性。
应用实例:
- 图形界面库:如上文所述,图形界面库可以通过桥接模式支持不同类型的图形和绘制样式。
- 软件渲染引擎:渲染引擎可以使用桥接模式,将渲染对象(如3D模型、纹理等)与渲染技术(如光照、着色等)分离。
3.2 避免多重继承
在某些编程语言中,多重继承可能不被支持或不推荐使用,因为它可能导致复杂的继承关系和难以解决的冲突问题。
桥接模式的优势:
- 避免多重继承:桥接模式提供了一种避免多重继承问题的方法,通过组合而非继承来实现代码复用。
- 减少继承层次:桥接模式减少了继承层次,使得系统更加扁平化,简化了类之间的关系。
- 灵活性与安全性:相比于继承,组合提供了更高的灵活性,并且可以更好地控制访问权限和行为。
应用实例:
- 企业应用架构:在企业应用中,业务逻辑和数据访问层可能需要独立变化。桥接模式可以避免因使用多重继承带来的复杂性。
- 游戏开发:游戏中的角色(如敌人、主角等)和行为(如移动、攻击等)可以通过桥接模式进行分离,避免使用多重继承。
桥接模式通过将抽象与实现分离,提供了一种灵活且有效的方式来处理系统中独立变化的多个维度,并避免了多重继承可能带来的问题。在下一部分中,我们将讨论桥接模式的优点与缺点。
第四部分:桥接模式的优点与缺点
4.1 优点
提高系统的灵活性
- 独立变化:桥接模式使得抽象部分和实现部分可以独立变化,互不影响,从而提高了系统的灵活性。
增强可扩展性
- 扩展实现:当需要增加新的实现时,只需添加具体实现化类而无需修改抽象类,遵循开闭原则。
避免多重继承问题
- 减少继承:在不支持多重继承的语言中,桥接模式通过使用组合代替继承,避免了多重继承的问题。
简化系统
- 解耦组件:桥接模式通过解耦系统的不同组件,简化了系统的结构,使得各部分更容易理解和维护。
提升代码复用性
- 共享实现:相同的实现类可以在不同的抽象类中被复用,提高了代码的复用性。
4.2 缺点
增加系统的复杂性
- 类的数量:桥接模式可能会增加系统中类的数量,因为每个抽象类都需要对应的实现类。
设计难度
- 理解难度:对于不熟悉桥接模式的开发者来说,理解这种模式的结构和意图可能有一定难度。
实现复杂性
- 实现细节:在桥接模式中,实现类的实现细节可能变得复杂,尤其是当多个抽象类需要协调时。
性能考虑
- 性能开销:在某些情况下,桥接模式可能会引入额外的性能开销,尤其是在需要频繁切换实现时。
过度设计
- 适用性:如果问题不需要复杂的抽象和实现分离,使用桥接模式可能是一种过度设计。
桥接模式是一种强大的设计模式,它通过将抽象与实现分离,提高了系统的灵活性和可扩展性。然而,它也需要谨慎使用,以避免增加系统的复杂性和设计难度。在实际应用中,根据具体需求和场景选择是否使用桥接模式是非常重要的。在下一部分中,我们将比较桥接模式与其他设计模式,并提供一些最佳实践和建议。
第五部分:桥接模式与其他模式的比较
5.1 与适配器模式的比较
适配器模式
- 目的:适配器模式主要用于使不兼容的接口能够一起工作,它通常转换一个类的接口以符合另一个接口的需求。
- 实现:适配器模式通常包含一个包装对象,该对象将请求从客户端转发到被适配者。
桥接模式
- 目的:桥接模式主要用于将抽象部分与实现部分分离,以便它们可以独立地变化。
- 实现:桥接模式通过组合关系将实现化角色与抽象化角色解耦,允许独立地扩展抽象和实现。
对比
- 解耦方式:适配器模式主要用于解决接口不兼容的问题,而桥接模式用于解耦抽象和实现,以便它们可以独立扩展。
- 使用场景:适配器模式适用于需要将一个类的接口适配到另一个接口的场景,而桥接模式适用于需要独立变化的多个维度。
5.2 与外观模式的对比
外观模式
- 目的:外观模式提供了一个统一的高层接口,用于访问子系统中的一组接口,它隐藏了子系统内部的复杂性。
- 实现:外观模式定义了一个类,该类作为客户端与子系统交互的单一入口点。
桥接模式
- 目的:桥接模式用于将抽象部分与实现部分分离,以便它们可以独立地变化和扩展。
- 实现:桥接模式通过抽象化和实现化角色的组合,允许抽象和实现独立变化。
对比
- 简化访问:外观模式主要用于简化客户端对复杂系统的访问,而桥接模式主要用于解耦抽象和实现。
- 使用场景:外观模式适用于需要简化客户端与复杂子系统交互的场景,而桥接模式适用于需要独立扩展抽象和实现的场景。
桥接模式和外观模式都用于简化系统设计,但它们的关注点和应用场景不同。桥接模式强调抽象与实现的独立性,而外观模式强调简化客户端对复杂系统的访问。在实际应用中,根据具体需求和场景选择合适的设计模式是非常重要的。在下一部分中,我们将提供桥接模式的最佳实践和建议。
第六部分:桥接模式的最佳实践和建议
6.1 最佳实践
保持抽象和实现的独立性
- 分离关注点:确保抽象层专注于定义业务功能,而实现层专注于具体的操作细节。
明确角色职责
- 职责划分:清晰地划分抽象化和实现化角色的职责,避免角色之间的职责重叠。
提供灵活的组合
- 动态绑定:利用组合的灵活性,允许在运行时动态地更换实现化角色。
避免紧密耦合
- 松散耦合:通过桥接模式减少组件之间的直接依赖,实现松散耦合。
使用组合而非继承
- 优先使用组合:在可能的情况下,优先使用组合来实现桥接模式,而不是依赖继承。
6.2 避免滥用
避免过度设计
- 合理应用:仅在系统确实需要独立变化的多个维度时使用桥接模式,避免无谓的过度设计。
避免增加不必要的复杂性
- 简化设计:如果系统简单,避免引入复杂的桥接模式,以免增加理解成本和维护难度。
避免过度封装
- 适度封装:在保持实现细节隐藏的同时,确保不会过度封装,导致客户端难以使用。
6.3 替代方案
使用策略模式
- 定义一系列算法:当需要根据不同的策略动态改变对象行为时,可以使用策略模式。
使用状态模式
- 管理状态转换:当对象的状态变化涉及复杂的状态转换逻辑时,可以使用状态模式。
使用装饰者模式
- 动态添加职责:当需要动态地给对象添加额外职责时,可以使用装饰者模式。
使用组合模式
- 表示部分-整体结构:当需要表示对象的部分-整体层次结构时,可以使用组合模式。
使用依赖注入
- 管理依赖关系:通过依赖注入来管理对象的依赖关系,而不是通过硬编码的方式。
桥接模式是一种强大的设计模式,可以提高系统的灵活性和可扩展性。然而,合理使用桥接模式并避免其缺点是至关重要的。了解其替代方案可以帮助开发者根据具体需求和场景选择最合适的设计模式。在实际开发中,应根据具体情况灵活运用桥接模式,以达到最佳的设计效果。
结语
桥接模式提供了一种有效的方法来解耦抽象与实现,使得它们可以独立地变化和扩展。通过本文的深入分析,希望读者能够对桥接模式有更全面的理解,并在实际开发中做出合理的设计选择。
博主还写了其他Java设计模式文章,请各位大佬批评指正:
Java二十三种设计模式-单例模式(1/23)
Java二十三种设计模式-工厂方法模式(2/23)
Java二十三种设计模式-抽象工厂模式(3/23)
Java二十三种设计模式-建造者模式(4/23)
Java二十三种设计模式-原型模式(5/23)
Java二十三种设计模式-适配器模式(6/23)
Java二十三种设计模式-装饰器模式(7/23)
Java二十三种设计模式-代理模式(8/23)
Java二十三种设计模式-外观模式(9/23)
相关文章:

Java二十三种设计模式-桥接模式(10/23)
桥接模式:解耦抽象与实现的灵活设计 引言 桥接模式(Bridge Pattern)是一种结构型设计模式,用于将抽象部分与其实现部分分离,使它们可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模…...
Java 面试指南
Java 面试指南 目录 引言Java 基础知识 数据类型运算符控制结构面向对象编程 Java 高级特性 异常处理集合框架泛型多线程与并发 Java 标准类库 java.lang 包java.util 包java.io 包 Java Web 开发 ServletJSPSpring 框架 数据库连接与JDBC JDBC 基础数据库连接池 设计模式 单…...

计算机毕业设计选题推荐-自习室座位预约系统-Java/Python项目实战
✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

android13 删除兼容性警告窗口 deprecation warning 去除弃用警告
总纲 android13 rom 开发总纲说明 目录 1.前言 2.情况 3.问题分析 4.代码更改 5.编译测试 6.彩蛋 1.前言 在 Android 13 中,为了提高用户体验和应用的兼容性,系统引入了一些新的隐私和安全特性。这些特性可能会影响旧版应用的行为,因此当用户运行可能不完全兼容 An…...

JESD204B/C协议学习笔记
JESD204B基础概念 204B包含传输层,链路层,物理层。 应用层是对 JESD204B 进行配置的接口,在标准协议中是不含此层,只是为了便于理解,添加的一个层。 协议层指工程中生成的IP核JESD204B,负责处理输入的用户…...

网络安全-渗透测试工具及插件介绍和使用方法
1、Burp Suite Burp Suite 是用于攻击web 应用程序的集成平台。 是一款广泛使用的网络安全工具套件,主要用于测试Web应用程序的安全性。它可以帮助安全研究人员、渗透测试人员和开发人员发现和利用Web应用程序中的安全漏洞。 (1)下载和安装&a…...

JAVA WEB初步实验
Spring应用开发环境准备 安装配置Spring应用开发环境 熟悉IntelliJ IDEA开发工具 打开idea工具,创建普通Java工程 配置普通Java工程运行环境 得到基本的Java运行环境配置正常 修改pom.xml文件,搭建Spring IOC运行环境 更新pom文件 新建User、TestSpr…...
30 个 JavaScript 技巧,让你的代码更具可读性
1 、使用 !! 转换为布尔值 使用双重否定快速将任何值转换为布尔值。 let truthyValue !!1; // true let falsyValue !!0; // false 2 、 默认函数参数 设置函数参数的默认值以避免定义错误。 function greet(name "Guest") {return Hello, ${name}!; }greet(…...
电商行业中选择分账系统的关键因素!
分账是指将一笔交易的款项拆分成多个部分,按照预先设定的比例或规则分配给相关方。在电商行业中,分账通常是指将交易金额分给卖家、平台和其他相关方。 具体来说,分账可以帮助实现以下目标: 卖家结算:将顾客支付的货…...
通过继承实现状态模式(C++)
注意:先做类的声明和抽象基类的声明 抽象基类的函数方法中引入类,具体方法在类的实现后面声明。 在抽象基类的子类的函数中可以调用类的成员函数。 #include <iostream>using namespace std;class Contex;class state { public:virtual void Ha…...

全国多地公布2024下半年软考报名具体时间
下半年开考科目: 高级资格:系统分析师、系统架构设计师、网络规划设计师、系统规划与管理师 中级资格:软件设计师、网络工程师、信息安全工程师、信息系统监理师、多媒体应用设计师、系统集成项目管理工程师 初级资格:网络管理…...

【Python】requests的response.text 和 urllib.request 的 response.read()的区别
刚写代码的时候,我经常会把requests 和 urllib下的request 包搞混,这两个请求响应的方法看起来很相似,但是写获取的方法是不一样的。 前者requests 是用response.text 来获取源码,而 urllib.request是用 response.read() 来获取h…...

Obsidian插件安装与开发
大概背景 事情的起因还是因为做笔记,我喜欢利用插件Obsidian Git自动同步笔记到Gitee,写md文档有个问题就是关于图片如何存储。 我个人习惯是将所有图片都保存到指定的文件夹下,如图👇 由于Obsidian对粘贴图片默认格式为这样的&…...

lvs的dr模式实现
目录 一、实验环境准备 1、五台红帽9系统的主机 2、关闭所有的防火墙以及关闭selinux 二、在lvs中配置 1、在lvs中安装lvs软件并设置开机启动 2、在lvs中打开内核路由功能,并把它写入/etc/sysctl.conf文件中 3、webserver1和webserver2下载httpd 4、在lvs主机…...

免费写作神器,自动生成高质量文章
在当今数字化的时代,信息的传播和创作变得前所未有的重要。无论是企业的营销推广、个人的博客写作,还是学术研究报告,优质的文章都能发挥巨大的作用。而随着人工智能技术的飞速发展,免费的ai写作工具应运而生,为我们带…...
C#属性
属性(property)的概念是:它是一个方法或一对方法,在客户端代码看来,他(们)是一个字段。 下面把前面示例中变量名为_firstName的名字字段改为私有。FirstName属性包含get和set访问器,来检索和设置支持字段的…...
Spring的代理模式
目录 1、什么是代理模式? 2、为什么要用代理模式? 3、有哪几种代理模式? 4、静态代理 5、动态代理 (1)Proxy动态代理 (2)Enhancer动态代理 (3)dbUtil和动态代理的…...
el-table合计放在标题上方且合并列以及渲染后端返回的数据
el-table二次封装的父组件中的属性 <y-table :table-data"tableData" :table-model"tableModel" :isShowSummary"true" :getSummaries"getSummaries"></y-table>el-table合计放在标题上方 <style lang"scss"…...

magic-api相关应用与配置
目录 项目启动 工具:IDEA 运行项目 关于配置 项目启动 工具:IDEA 新建——》项目——》导入——》运行 运行项目 http://localhost:9999/magic/web/index.htmlhttp://localhost:9999/magic/web/index.html 关于配置 配置多数据源 在线配置多数据…...

AI大模型赋能开发者|海云安创始人谢朝海受邀在ISC.AI 2024大会就“大模型在软件开发安全领域的应用”主题发表演讲
近日,ISC.AI 2024 第十二届互联网安全大会在北京国家会议中心盛大开幕。作为全球规格最高、规模最大、影响力最深远的安全峰会之一,本次大会以“打造安全大模型 引领安全行业革命”为主题,聚焦安全与AI两大领域,吸引了众多行业领袖…...
leetcode 386. 字典序排数 中等
给你一个整数 n ,按字典序返回范围 [1, n] 内所有整数。 你必须设计一个时间复杂度为 O(n) 且使用 O(1) 额外空间的算法。 示例 1: 输入:n 13 输出:[1,10,11,12,13,2,3,4,5,6,7,8,9]示例 2: 输入:n 2…...
慢慢欣赏linux 之 last = switch_to(prev, next)分析
last switch_to(prev, next); 为什么需要定义last作为调用switch_to之前的prev的引用 原因如下: struct task_struct * switch_to(struct task_struct *prev,struct task_struct *next) {... ...return cpu_switch_to(prev, next);> .global cpu_switch_tocpu_…...

leetcode238-除自身以外数组的乘积
leetcode 238 思路 可以在不使用除法的情况下,利用前缀积和后缀积来实现解答 前缀积:对每个位置,计算当前数字左侧的所有数字的乘积后缀积:对每个位置,计算当前数字右侧的所有数字的乘积 结合这两种思想࿰…...

leetcode_66.加一
题目链接 这道题归类在力扣的数学类中,应该算是一道思维的简单题吧 题是这样的,根据题目我们不难理解,这个题就是在最后一位加 1 然后返回,正如示例所说的那样,当然这很符合我们人的思维,写这种算法题最重要…...
MySQL EXPLAIN 命令详解
文章目录 MySQL EXPLAIN 命令详解EXPLAIN 输出的基本结构id2. select_type3. table4. partitions5. type6. possible_keys7. key8. key_len9. ref10. rows11. filtered12. Extra 使用 EXPLAIN 的注意事项示例 MySQL EXPLAIN 命令详解 EXPLAIN 是 MySQL 中一个非常有用的命令&a…...
Redis 知识点一
参考 Redis - 常见缓存问题 - 知乎 Redis的缓存更新策略 - Sherlock先生 - 博客园 三种缓存策略:Cache Aside 策略、Read/Write Through 策略、Write Back 策略-CSDN博客 1.缓存问题 1.1.缓存穿透 大量请求未命中缓存,直接访问数据库。 解决办法&…...

在Vue或React项目中使用Tailwind CSS实现暗黑模式切换:从系统适配到手动控制
在现代Web开发中,暗黑模式(Dark Mode)已成为提升用户体验的重要功能。本文将带你使用Tailwind CSS在React项目(Vue项目类似)中实现两种暗黑模式控制方式: 系统自动适配 - 根据用户设备偏好自动切换手动切换 - 通过按钮让用户自由选择 一、项目准备 使…...

微软重磅发布Magentic UI,交互式AI Agent助手实测!
微软重磅发布Magentic UI,交互式AI Agent助手实测! 何为Magentic UI? Magentic UI 是微软于5.19重磅发布的开源Agent助手,并于24日刚更新了第二个版本0.04版 从官方的介绍来看,目标是打造一款 以人为中心 的智能助手,其底层由多个不同的智能体系统驱动,能够实现网页浏览…...

基于PostGIS的各地级市路网长度统计及Echarts图表可视化实践-以湖南省为例
目录 前言 一、路网长度计算 1、地级市列表查询 2、地级市路网长度查询 二、Echarts可视化实现 1、Echarts后端生成 2、引入Colormap配色 3、前端微调 三、总结 前言 在当今快速发展的社会中,交通路网的建设与布局对于一个地区的经济发展、居民生活以及城市…...

Java 日期时间类全面解析
Java 日期时间类全面解析:从传统到现代的演进 一、发展历程概览 二、传统日期类(Java 8前) 1. java.util.Date - 日期表示类 Date now new Date(); // 当前日期时间 System.out.println(now); // Wed May 15 09:30:45 CST 2023// 特定时间…...