设计模式——桥接模式
引用
桥我们大家都熟悉,顾名思义就是用来将河的两岸联系起来的。而此处的桥是用来将两个独立的结构联系起来,而这两个被联系起来的结构可以独立的变化,所有其他的理解只要建立在这个层面上就会比较容易。
基本介绍
- 桥接模式(Bridge)是指将实现与抽象放在两个不同的类层次中,是两个层次可以独立改变。
- 该模式基于类的最小设计原则(扩展功能时尽量少的增加类),通过使用封装、聚合、继承等行为让不同的类承担不同的职责。
- 主要特点是把抽象和行为实现分离开来,从而可以保持各部分的独立性以及对他们的功能扩展。
- 桥梁模式的用意是将抽象化与实现化脱耦,使得二者可以独立地变化。
原理类图
桥接(Bridge)模式包含以下主要角色:
-
client:桥接模式的调用者
- Implementor:实现化角色,它是接口或者抽象类,定义角色必需的行为和属性;这个接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor接口仅提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,Abstraction不仅拥有自己的方法,还可以调用Implementor中定义的方法,使用关联关系来替代继承关系;
- ConcreteImplementor:具体实现化角色,实现接口或抽象类定义的方法或属性。在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplementor对象将替换其父类对象,提供给抽象类具体的业务操作方法;
- Abstraction:抽象化角色,定义出该角色的行为,同时保存一个对实现化角色的引用;它一般是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,它既可以包含抽象业务方法,也可以包含具体业务方法;
- RefinedAbstraction:扩充抽象类角色,引用实现化角色对抽象化角色进行扩充。通常情况下,它不再是抽象类而是具体类,它实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中可以调用在Implementor中定义的业务方法;
从UML图看,这里的抽象类和接口是聚合关系,就是调用和被调用的关系;RefinedAbstraction的父类聚合了接口,RefinedAbstraction调用接口的具体实现
优缺点
通过上面的讲解,我们能很好的感觉到桥接模式遵循了里氏替换原则和依赖倒置原则,最终实现了开闭原则,对修改关闭,对扩展开放。这里将桥接模式的优缺点总结如下。
优点:
- 分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。
- 在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。
- 桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。
缺点:
- 桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
- 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。
模式的实现
桥接模式的代码如下:
package bridge;
public class BridgeTest {public static void main(String[] args) {Implementor imple = new ConcreteImplementorA();Abstraction abs = new RefinedAbstraction(imple);abs.Operation();}
}
//实现化角色
interface Implementor {public void OperationImpl();
}
//具体实现化角色
class ConcreteImplementorA implements Implementor {public void OperationImpl() {System.out.println("具体实现化(Concrete Implementor)角色被访问");}
}
//抽象化角色
abstract class Abstraction {protected Implementor imple;protected Abstraction(Implementor imple) {this.imple = imple;}public abstract void Operation();
}
//扩展抽象化角色
class RefinedAbstraction extends Abstraction {protected RefinedAbstraction(Implementor imple) {super(imple);}public void Operation() {System.out.println("扩展抽象化(Refined Abstraction)角色被访问");imple.OperationImpl();}
}
程序的运行结果如下:
扩展抽象化(Refined Abstraction)角色被访问
具体实现化(Concrete Implementor)角色被访问
案例场景模拟
假设设计一个日志系统,这个系统可以记录多种日志类型,如交易日志,数据库日志,用户操作日志等,同时,这个系统还支持多种日志的表现形式。如xml文件,文本文件,数据库库数据,E-mail等。
抽象:日志的种类。
实现:日志的表现方式。
实现代码如下:
Log源代码
public abstract class Log{protected LogSave logSave;public Log(LogSave logSave){this.logSave=logSave;}public abstract void writeToLog();
}
LogSave源代码
public abstract class LogSave{public abstract void write();
}
下面是三个Log的子类
TradLog源代码
public class TradLog extends Log{public TradLog(LogSave logSave){super(logSave);}@Overridepublic void writeToLog(){System.out.println("写入TradLog数据");this.logSave.write();}
}
DbLog源代码
public class DbLog extends Log{public DbLog(LogSave logSave){super(logSave);}@Overridepublic void writeToLog(){System.out.println("写入DbLog数据");this.logSave.write();}
}
UserLog源代码
public class UserLog extends Log{public UserLog(LogSave logSave){super(logSave);}@Overridepublic void writeToLog(){System.out.println("写入UserLog数据");this.logSave.write();}
}
下面是LogSave的三个实现类
XmlImpl源代码
public class XmlImpl extends LogSave{@Overridepublic void write(){System.out.println("使用xml方式存储");}
}
TextImpl源代码
public class TextImpl extends LogSave{@Overridepublic void write(){System.out.println("使用文本方式存储");}
}
EmailImpl源代码
public class EmailImpl extends LogSave{@Overridepublic void write(){System.out.println("使用发邮件的方式存储");}
}
实现不能和抽象发生耦合,而只能由抽象和实现发生耦合。
下面是启动类展示最终结果:
Client源代码
public class Client{public static void main(String[] args){Log log=new UserLog(new XmlImpl());log.writeToLog();Log log2=new DbLog(new EmailImpl());log2.writeToLog();}
}
运行结果如下:
写入UserLog数据
使用xml方式存储
写入DbLog数据
使用发邮件的方式存储
应用场景
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
- 常用的场景:
- JDBC驱动程序
- 日志框架
- 银行转账系统
- 转账分类:网上转账、柜台转账、ATM转账
- 用户类型:普通用户、银卡用户、金卡用户
- 消息管理
- 消息类型:即时消息、延时消息
- 消息分类:手机短信、邮件信息、QQ消息
桥接模式模式的扩展
在软件开发中,有时桥接(Bridge)模式可与适配器模式联合使用。当桥接(Bridge)模式的实现化角色的接口与现有类的接口不一致时,可以在二者中间定义一个适配器将二者连接起来,其具体结构图如图桥接模式与适配器模式联用的结构图所示。
小结
- 对于系统的高层来说,只需要知道抽象部分和实现部分的接口就够了,其他部分由具体业务来完成
- 桥接模式代替多层继承方案,可以减少子类的个数,降低系统的管理和维护成本
- 桥接模式要求正确识别出系统中的两个独立变化维度,因此其使用范围有一定的局限性,适用于一定的应用场景
相关文章:
设计模式——桥接模式
引用 桥我们大家都熟悉,顾名思义就是用来将河的两岸联系起来的。而此处的桥是用来将两个独立的结构联系起来,而这两个被联系起来的结构可以独立的变化,所有其他的理解只要建立在这个层面上就会比较容易。 基本介绍 桥接模式(Br…...
改进YOLO系列:2.添加ShuffleAttention注意力机制
添加ShuffleAttention注意力机制 1. ShuffleAttention注意力机制论文2. ShuffleAttention注意力机制原理3. ShuffleAttention注意力机制的配置3.1common.py配置3.2yolo.py配置3.3yaml文件配置1. ShuffleAttention注意力机制论文 论文题目:SA-NET: SHUFFLE ATTENTION …...
利用Opencv实现人像迁移
前言: Hello大家好,我是Dream。 今天来学习一下如何使用Opencv实现人像迁移,欢迎大家一起参与探讨交流~ 本文目录: 一、实验要求二、实验环境三、实验原理及操作1.照片准备2.图像增强3.实现美颜功能4.背景虚化5.图像二值化处理6.人…...
Lnton羚通算法算力云平台在环境配置时 OpenCV 无法显示图像是什么原因?
问题: cv2.imshow 显示图像时报错,无法显示图像 0%| | 0/1 [00:00<…...
【JavaEE进阶】MyBatis的创建及使用
文章目录 一. MyBatis简介二. MyBatis 使用1. 数据库和数据表的创建2. 创建Mybatis项目2.1 添加MyBatis框架支持2.2 设置MyBatis配置信息 3. MyBatis开发流程4. MyBatis查询数据库测试 三. MyBatis 流程1. MyBatis 查询数据库流程2. MyBatis 框架交互流程图 一. MyBatis简介 M…...
职业学院物联网实训室建设方案
一、概述 1.1专业背景 物联网(Internet of Things)被称为继计算机、互联网之后世界信息产业第三次浪潮,它并非一个全新的技术领域,而是现代信息技术发展到一定阶段后出现的一种聚合性应用与技术提升,是随着传感网、通…...
3 个 ChatGPT 插件您需要立即下载3 ChatGPT Extensions You need to Download Immediately
在16世纪,西班牙探险家皮萨罗带领约200名西班牙士兵和37匹马进入了印加帝国。尽管印加帝国的军队数量达到了数万,其中包括5,000名精锐步兵和3,000名弓箭手,他们装备有大刀、长矛和弓箭等传统武器。但皮萨罗的军队中有100名火枪手,…...
屏蔽socket 实例化时,握手阶段报错信息WebSocket connection to ‘***‘ failed
事情起因是这样的: 我们网站是需要socket链接实行实时推送服务,有恶意竞争对手通过抓包或者断网,获取到了我们的socket链接地址,那么他就可以通过java写一个脚本无限链接这个socket地址。形成dos攻击。使socket服务器资源耗尽&…...
单发多框检测(SSD)【动手学深度学习】
单发多框检测模型主要由一个基础网络块和若干多尺度特征块串联而成。基本网络用于从输入图像中提取特征,可以使用深度卷积神经网络,原论文中选用了在分类层之前阶段的VGG,现在也常用ResNet替代。 我们可以设计基础网络,使它输出的高和宽较大,这样基于该特征图生成的锚框数…...
“RFID与光伏板的完美融合:探索能源科技的新时代!“
随着科技的不断发展,人类创造出了许多令人惊叹的发明。其中,RFID(Radio Frequency Identification)技术的应用在各个领域日益广泛。最近的研究表明,将RFID技术应用于光伏板领域,不仅可以提高光伏板的效率&a…...
算法leetcode|71. 简化路径(rust重拳出击)
文章目录 71. 简化路径:样例 1:样例 2:样例 3:样例 4:提示: 分析:题解:rust:go:c:python:java: 71. 简化路径:…...
网络技术Vlan技术STP(第一课)
一 Vlan技术的学习 对命令的增删改查 #### 1)创建vlan[SW1]vlan 2 [2-4094] 创建vlan[SW1]vlan batch 10 20 30 创建多个不连续的vlan[SW1]display vlan 查看vlan信息[SW1]vlan batch 50 to 60创建多个连续的vlan[SW1]vlan2[SW1-vlan2]description caiwu添加描述信…...
SpringBoo t+ Vue 微人事 (十一)
职位修改操作 在对话框里面做编辑的操作 添加对话框 <el-dialogtitle"修改职位":visible.sync"dialogVisible"width"30%"><div><el-tag>职位名称</el-tag><el-input size"small" class"updatePosIn…...
自动驾驶卡车量产-第一章-用户需求
1、中国干线物流行业现状 万亿级市场,规模巨大。由中重卡承运的干线运输占到整体公路货运市场的82%,全国中重卡保有量约730 万台1,市场规模达4.6 万亿元1,体量全球第一,超过同城物流及乘用出租市场规模之和。同样&…...
Nginx 配置文件的完整指南 (一)
文章目录 一、简介1.1 配置文件一览 二、全局配置2.0 user2.1 worker_processes2.2 events模块2.3 http模块 三、server模块3.1 listen3.2 server_name3.3 location:请求处理位置 Nginx 配置文件的完整指南 (二) 一、简介 Nginx是一款高性能的Web服务器和反向代理服…...
css3+js 画出爱心特效
要使用CSS3和JavaScript绘制爱心特效,可以使用CSS3的动画和过渡效果来创建爱心的形状,并使用JavaScript来控制动画的触发和交互。以下是一个简单的示例代码: HTML: <div class"heart"></div> <button onclick&quo…...
蔚来李斌卖手机:安卓系统,苹果售价,一年一发
作者 | Amy 编辑 | 德新 车圈大佬的玩法真让人寻不着套路! 苹果的库克和小米的雷布斯,甚至是FF贾老板准备许久,都想分一块新能源车的蛋糕,蔚来李斌却反手进军手机界,从宣布造手机到手机入网仅仅隔了一年。 近期&a…...
0008__浏览器层面缓存 Etag If-None-Match等详解
浏览器层面缓存 Etag & If-None-Match等详解_if-none-match:_shadow_zed的博客-CSDN博客...
Idea 快捷键整理
Idea快捷键和自动代码补全汇总 idea快捷键汇总 Ctrl 快捷键说明Ctrl F在当前文件进行文本查找 (必备)Ctrl R在当前文件进行文本替换 (必备)Ctrl Z撤销 (必备)Ctrl Y删除光标所在行 或 删除选中的行 &am…...
管理类联考——逻辑——真题篇——按知识分类——汇总篇——一、形式逻辑——假言——第一节 充分条件
文章目录 第一节 充分条件假言命题-那么,就,则真题(2013-29)-假言-充分假言-那么,就,则-变形推理真题(2014-44)-假言-充分假言-那么,就,则-(1)建模-“那么/就/则”-前推后真题(2018-37)-假言-充分假言-那么,就,则-(1)建模-“那么/就/则”-前推后;-(2)A→…...
LSTM模型
目录 LSTM模型 LSTM结构图 LSTM的核心思想 细胞状态 遗忘门 输入门 输出门 RNN模型 LRNN LSTM模型 什么是LSTM模型 LSTM (Long Short-Term Memory)也称长短时记忆结构,它是传统RNN的变体,与经典RNN相比能够有效捕捉长序列之间的语义关联,缓解梯度消失或爆炸现象.同时LS…...
抢红包小程序
抢红包小程序 红包大战 # urls.pyfrom django.urls import pathfrom . import viewsurlpatterns [ path(login/, views.login, namelogin), path(create_red_packet/, views.create_red_packet, namecreate_red_packet), path(join_red_packet/<int:red_packet_id…...
UVA 10006 埃氏筛法+快速幂
本题目使用费马定理时,我随机定义了10个数字,循环用费马小定理判断,数组中的值不用和我的相同,随机即可。 #include <iostream> using namespace std; typedef unsigned long long ll; bool isPrime[65007]; ll a[10]; voi…...
C++--红黑树
1.什么是红黑树 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因…...
Unity 找不到 Navigation 组件的解决
当我们想利用unity 里面的Navigation 组件来实现我们的物体的自动导航时,有时竟然会发现我们的菜单栏里面找不到 该组件 这时我们应该怎么办? 请确保你的项目中已经导入了Unity的AI模块。要导入该模块,请打开"Project Settings"&am…...
【js】时间和时间戳转换、日期格式化
1、时间戳转换日期方法 (格式:2023-08-17) function timestampToDate(date) {var date new Date(date);var YY date.getFullYear() -;var MM (date.getMonth() 1 < 10 ? 0 (date.getMonth() 1) : date.getMonth() 1) -;var DD …...
glog体验第一天(0)glog介绍和安装
在Ubuntu上安装glog,可以按照以下步骤进行操作: 打开终端,使用以下命令更新本地软件包列表: sudo apt-get update然后,使用以下命令安装glog库及其开发工具: sudo apt-get install -y libgoogle-glog-de…...
Android 13像Settings一样获取SIM卡信息
一.背景 由于客户定制的Settings里面需要获取到SIM卡信息,所以需要实现此功能。 目录 一.背景 二.前提条件 三.调用api 二.前提条件 首先应用肯定要是系统应用,并且导入framework.jar包,具体可以参考: Android 应用自动开启辅助(无障碍)功能并使用辅助(无障碍)功能_…...
Can‘t find end of central directory : is this a zip file ? at XMLHttpRequest
导出woed出现这个报错,原因其实很简单,路径写错了, 这个word首先必须是docx格式,然后必须放在public文件包下 如果放在public文件包下还没有用,则放在public包下 参考帖子: https://www.cnblogs.com/hejun26/p/13647927.html...
基于SpringBoot+Thymeleaf仓库管理系统
✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 随着信息技术的快速发…...
ubuntu20.04磁盘满了 /dev/mapper/ubuntu--vg-ubuntu--lv 占用 100%
问题 执行 mysql 大文件导入任务,最后快完成了,查看结果发现错了!悲催!都执行了 两天了 The table ‘XXXXXX’ is full ? 磁盘满了? 刚好之前另一个 centos 服务器上也出现过磁盘满了,因此&a…...
【制作npm包4】api-extractor 学习
制作npm包目录 本文是系列文章, 作者一个橙子pro,本系列文章大纲如下。转载或者商业修改必须注明文章出处 一、申请npm账号、个人包和组织包区别 二、了解 package.json 相关配置 三、 了解 tsconfig.json 相关配置 四、 api-extractor 学习 五、npm包…...
神经网络基础-神经网络补充概念-52-正则化网络的激活函数
概念 正则化是一种用于减少过拟合(overfitting)的技术,可以在神经网络的各个层次中应用,包括激活函数。激活函数的正则化主要目的是减少神经网络的复杂度,防止网络在训练集上过度学习,从而提高泛化能力。 …...
代码随想录训练营day56| 583. 两个字符串的删除操作 72. 编辑距离
TOC 前言 代码随想录算法训练营day56 一、Leetcode 583. 两个字符串的删除操作 1.题目 给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 示例 1: 输入: word1 "sea",…...
神经网络基础-神经网络补充概念-55-为什么是ML策略
“ML策略”(Machine Learning Strategies)是指在解决机器学习问题时,采取的一系列方法、技巧和策略。选择适当的ML策略对于获得高质量的模型和结果非常重要。以下是为什么要考虑ML策略的一些原因: 问题适应性:不同的机…...
C++初阶语法——内部类
前言:内部类,顾名思义是定义在类中的类,许多人会以为它属于外部的类,实际上并不是,它们是两个独立的类,但是内部类受外部类类域的限制。 目录 一.概念二.特性1.内部类和外部类相互独立2.内部类是外部类的友…...
Java基础(十四)面向对象编程 OOP 多态
Java面向对象基础知识笔记(四) 1. 对象数组的使用 在Java中,我们可以创建包含对象的数组。对象数组是一种特殊类型的数组,其中每个元素都是一个对象的引用。你可以将任何类的对象存储在对象数组中,并通过索引来访问和操…...
【Android】解决Lint found fatal errors while assembling a release target
报错信息: Android在debug模式下打包没有问题,但是在打包release版本时出现一下问题: 结果图 原因 我项目的原因是因为把正式、测试地址放到代码里了,忘记选中正式环境的地址,导致打正式包有问题;大家如果…...
CF1195E OpenStreetMap 题解
很好的单调队列题。 题目传送门 题目意思: 给定一个 n m n\times m nm 的矩阵,求出所有大小为 a b a\times b ab 的子矩形中的最小值的和。 思路: 通过题目给的要求建立二维数组 h h h。通过单调队列一行一行地扫,将扫出来…...
微信营销系统如何使用效果会更好
微信作为中国最大的社交平台之一,已经成为企业私域营销的重要阵地。在这个庞大的社交网络中,如何使用微信营销系统,将直接影响到企业的营销效果。本文将深入探讨如何更好地利用微信营销系统,以实现更好的私域营销效果。 1. 确定营…...
Linux开机启动程序添加root权限
Linux添加开机启动程序 Debain、Ubuntu系列Linux开机之后会执行/etc/rc.local文件中的命令,所以,如果是想添加登陆用户所具有权限的操作,可以在文件中exit 0之前添加开机自动执行的脚本命令。或者将执行脚本的权限修改为当前登录用户具有执行…...
安卓13解决链接问题
作为Android用户,你可能已经注意到了一个问题——Android 13不再支持PPTP协议。但请别担心,作为一家专业的代理供应商,我们将与你分享解决方案,让你轻松解决L2TP问题,享受到高水平的连接体验。本文将为你提供实用的操作…...
《乡村振兴战略下传统村落文化旅游设计 》在2023年畅销榜排名465位
《乡村振兴战略下传统村落文化旅游设计 》在2023年畅销榜排名465位...
实现一个自动保存高CPU占用现场的简易工具
CPU 使用率在系统监控中是一个非常重要的指标。对于大多数 Web 应用来说,它们往往是 IO 密集型的,因此只会在某些时刻可能会出现 CPU 突然飙升的情况,随后很快就恢复正常。然而,当收到报警并想要排查问题时,CPU 飙升的…...
易服客工作室:如何在WordPress网站中举办虚拟活动
您是否正在寻找举办和管理虚拟活动的最佳方式? 也许您想在线举行下一次会议或举办有关您的产品和服务的网络研讨会。您可能担心它太贵,或者您没有技术知识来实现它。 在本文中,我们将列出您所需的在线服务的所有设备,并教您…...
Java IO流(一)IO基础
概述 IO流本质 I/O表示Input/Output,即数据传输过程中的输入/输出,并且输入和输出都是相对于内存来讲Java IO(输入/输出)流是Java用于处理数据读取和写入的关键组件常见的I|O介质包括 文件(输入|输出)网络(输入|输出)键盘(输出)显示器(输出)使用场景 文件拷贝(File&…...
区间覆盖 线段覆盖 二分
4195. 线段覆盖 - AcWing题库 P2082 区间覆盖(加强版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 做法: void solve() {int n; cin>>n;vector<array<LL,2>> seg(n);for(auto &t: seg) cin>>t[0]>>…...
F#奇妙游(20):主动模式
F#中主动模式的三种形式 F#中有一种特殊的模式匹配,叫做主动模式(Active Pattern)。主动模式可以让我们自定义模式匹配的方式,这样可以让我们的代码更加简洁,更加清晰。主动模式有三种形式,分别是…...
OLED透明屏与传统显示屏的区别:探索未来视觉体验的新里程碑
OLED透明屏作为一种新兴的显示技术,与传统显示屏相比,具有许多独特的特点和优势。 那么,在这篇文章中,尼伽便通过比较OLED透明屏和传统显示屏的区别,包括透明性、对比度、色彩表现力、节能环保等方面,为读…...
打开软件提示mfc100u.dll缺失是什么意思?要怎么处理?
当你打开某个软件或者运行游戏,系统提示mfc100u.dll丢失,此时这个软件或者游戏根本无法运行。其实,mfc100u.dll是动态库文件,它是VS2010编译的软件所产生的,如果电脑运行程序时提示缺少mfc100u.dll文件,程序…...