设计模式之桥接模式
文章目录
- 一、介绍
- 二、案例
- 1. 组件抽象化
- 2. 桥梁抽象化
一、介绍
桥接模式,属于结构型设计模式。通过提供抽象与实现之间的桥接结构,把抽象化与实现化解耦,使得二者可以独立变化。
《Head First 设计模式》:
将抽象和实现放在两个不同的类层次中,使它们可以独立地变化。
《图解设计模式》:
将类的功能层次结构和实现层次结构相分离,使二者能够独立地变化,并在两者之间搭建桥梁,实现桥接。
从专业术语对交接模式的解释来看,总是让人似懂非懂,即使懂了,从代码上实现又让人无法捉摸。典型的每个字都认识,连在一起就不懂了。
下面我们先通过一个简单的例子来演示一下桥接的结构是什么样的,然后对其进行改造,最终实现桥接模式。
二、案例
我们假设一部手机有三个重要部件:电池(Battery)、摄像头(Camera)、屏幕(Screen)。当我们拍摄一张高清照片时,需要充足的电量、高像素的摄像头、高分辨率的屏幕。
于是我们可以通过下面的代码完成拍照动作:
-
电池Battery
public class Battery {public Battery() {System.out.println("充足电量的电池");}public void electric() {System.out.println("电池供电...");} }
-
摄像头Camera
public class Camera {public Camera() {System.out.println("高清像素的摄像头");}public void catchImg() {System.out.println("摄像头捕获图像...");} }
-
屏幕Screen
public class Screen {public Screen() {System.out.println("高分辨率的屏幕");}public void show() {System.out.println("屏幕显示照片...");} }
-
手机Phone
public class Phone {private Battery battery;private Camera camera;private Screen screen;public Phone(Battery battery, Camera camera, Screen screen) {this.battery = battery;this.camera = camera;this.screen = screen;}public void takePic() {System.out.println("手机拍照开始...");// 电池供电battery.electric();// 摄像头捕获图像camera.catchImg();// 屏幕显示照片screen.show();} }
-
演示
public static void main(String[] args) {Battery battery = new Battery();Camera camera = new Camera();Screen screen = new Screen();Phone phone = new Phone(battery, camera, screen);phone.takePic(); }
-
结果输出
从该案例中可以看出,电池、摄像头、屏幕这三个组件是相互独立的,各自干各自的活,通过手机将他们连接起来就可以进行拍照,这时手机就表现为桥梁的角色。通过桥梁,三个组件相互独立。
1. 组件抽象化
在实际现实中,无论是电池、摄像头、还是屏幕,他们都有各自的品牌厂商,因此我们需要将他们抽象化。如电池有南孚和山羊;摄像头有索尼和徕卡;屏幕有三星和京东方。
所有我们需要做出修改:新建电池、摄像头、屏幕的抽象类;再分别按照品牌厂商对这些抽象类进行实现。
-
电池抽象类Battery,及其实现类:南孚电池(NanFu)、山羊电池(Sheep)
public interface Battery {void electric(); }public class NanFu implements Battery {public NanFu() {System.out.println("南孚电池实例化");}@Overridepublic void electric() {System.out.println("南孚电池正在供电...");} }public class Sheep implements Battery {public Sheep() {System.out.println("山羊电池实例化");}@Overridepublic void electric() {System.out.println("山羊电池正在供电...");} }
-
摄像头抽象类Camera,及其实现类:徕卡摄像头(Laika)、索尼摄像头(Sony)
public interface Camera {void catchImg(); }public class Laika implements Camera {public Laika() {System.out.println("徕卡摄像头实例化");}@Overridepublic void catchImg() {System.out.println("徕卡摄像头捕获图像...");} }public class Sony implements Camera {public Sony() {System.out.println("索尼摄像头实例化");}@Overridepublic void catchImg() {System.out.println("索尼摄像头捕获图像...");} }
-
屏幕抽象类Screen,及其实现类:京东方显示屏(JingDongFang)、三星显示屏(SanXing)
public interface Screen {void show(); }public class JingDongFang implements Screen {public JingDongFang() {System.out.println("京东方显示屏实例化");}@Overridepublic void show() {System.out.println("京东方显示屏显示照片...");} }public class SanXing implements Screen {public SanXing() {System.out.println("三星显示屏实例化");}@Overridepublic void show() {System.out.println("三星显示屏显示照片...");} }
这样一来,手机的构造方法的参数就由原来的具体实现类变成了抽象类。
public Phone(Battery battery, Camera camera, Screen screen) {this.battery = battery;this.camera = camera;this.screen = screen;
}
该构造方法参数的实际类型由调用方创建的实例为准。
public static void main(String[] args) {// 使用南孚电池Battery battery = new NanFu();// 索尼相机Camera camera = new Sony();// 京东方显示屏Screen screen = new JingDongFang();Phone phone = new Phone(battery, camera, screen);phone.takePic();
}
输出如下
2. 桥梁抽象化
其实不仅电池、摄像头、屏幕有自己的品牌厂商,手机也不例外,如华为、oppo、vivo等,因此我们也需要将手机这个桥梁的角色抽象化。但是如果我们将该桥梁设计成一个接口,由不同的手机品牌实现该接口,那么就可能会导致不同的实现类具有不同参数的构造方法,如此一来,所有品牌手机的功能虽然受到约束(实现类手机接口),但是他们的组成结构却千差万别。如下所示
public interface MyPhone {/*** 拍照*/void takePic();/*** 通话*/void call();/*** 微信聊天*/void wechat();
}public class Oppo implements MyPhone{private ComponentA componentA;private ComponentB componentB;public Oppo(ComponentA componentA, ComponentB componentB) {this.componentA = componentA;this.componentB = componentB;}@Overridepublic void takePic() {// 照相}@Overridepublic void call() {// 打电话}@Overridepublic void wechat() {// 聊微信}
}public class Vivo implements MyPhone{private ComponentC componentC;private ComponentD componentD;public Oppo(ComponentC componentC, ComponentD componentD) {this.componentC = componentC;this.componentD = componentD;}@Overridepublic void takePic() {// 照相}@Overridepublic void call() {// 打电话}@Overridepublic void wechat() {// 聊微信}
}
从上面的代码来看,oppo和vivo虽然实现了**手机(MyPhone)**定义的所有功能,但是却乱七八糟的,oppo手机内部组件是ComponentA
和ComponentB
,vivo手机内部组件却是ComponentC
和ComponentD
。这样的话手机行业岂不乱套了。
所以我们对桥梁的抽象化不应采用接口,而是抽象类。
使用抽象类有一个好处是,可以使所有子类拥有相同的内部属性,而且对所有子类的构造方法也做出了约束。
如下所示,我们将手机抽象化一个手机接口(Phone)来定义各个功能,再通过一个抽象子类(AbstractPhone)实现手机接口定义的功能,并规范构造方法,由华为(HuaWei)、**小米(XiaoMi)**两个品牌继承该抽象子类。
public interface Phone {/*** 拍照*/void takePic();
}public abstract class AbstractPhone implements Phone {private Battery battery;private Camera camera;private Screen screen;public AbstractPhone(Battery battery, Camera camera, Screen screen) {this.battery = battery;this.camera = camera;this.screen = screen;}@Overridepublic void takePic() {System.out.println("手机拍照开始...");// 电池供电battery.electric();// 摄像头捕获图像camera.catchImg();// 屏幕显示照片screen.show();}
}public class HuaWei extends AbstractPhone {public HuaWei(Battery battery, Camera camera, Screen screen) {super(battery, camera, screen);System.out.println("华为手机实例化");}
}public class XiaoMi extends AbstractPhone {public XiaoMi(Battery battery, Camera camera, Screen screen) {super(battery, camera, screen);System.out.println("小米手机实例化");}
}
通过接口(定义功能)、抽象子类(桥梁)、**实现类(实现功能)**的方式,就是交接设计模式的实现。
下面我们进行代码测试
public static void main(String[] args) {Battery battery = new NanFu();Camera camera = new Sony();Screen screen = new JingDongFang();// 华为将南孚电池、索尼相机、京东方显示屏桥接起来形成一部手机Phone phone = new HuaWei(battery, camera, screen);// 使用华为手机拍照phone.takePic();
}
以上就是桥接模式的演变过程,希望通过本篇文章的阅读,能使各位朋友对桥接模式有更深入的理解。
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————
相关文章:

设计模式之桥接模式
文章目录 一、介绍二、案例1. 组件抽象化2. 桥梁抽象化 一、介绍 桥接模式,属于结构型设计模式。通过提供抽象与实现之间的桥接结构,把抽象化与实现化解耦,使得二者可以独立变化。 《Head First 设计模式》: 将抽象和实现放在两…...

pom.xml配置文件失效,显示已忽略的pom.xml --- 解决方案
现象: 在 Maven 创建模块Moudle时,由于开始没有正确创建好,所以把它删掉了,然后接着又创建了与一个与之前被删除的Moudle同名的Moudle时,出现了 Ignore pom.xml,并且新创建的 Module 的 pom.xml配置文件失效…...

文本编辑器Vim常用操作和技巧
文章目录 1. Vim常用操作1.1 Vim简介1.2 Vim工作模式1.3 插入命令1.4 定位命令1.5 删除命令1.6 复制和剪切命令1.7 替换和取消命令1.8 搜索和搜索替换命令1.9 保存和退出命令 2. Vim使用技巧 1. Vim常用操作 1.1 Vim简介 Vim是一个功能强大的全屏幕文本编辑器,是L…...

【算法系列篇】位运算
文章目录 前言什么是位运算算法1.判断字符是否唯一1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 丢失的数字2.1 题目要求2.2 做题思路2.3 Java代码实现 3. 两数之和3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 只出现一次的数字4.1 题目要求4.2 做题思路4.3 Java代码实现 5.…...

机器学习的测试和验证(Machine Learning 研习之五)
关于 Machine Learning 研习之三、四,可到秋码记录上浏览。 测试和验证 了解模型对新案例的推广效果的唯一方法是在新案例上进行实际尝试。 一种方法是将模型投入生产并监控其性能。 这很有效,但如果你的模型非常糟糕,你的用户会抱怨——这…...

RNN循环神经网络
目录 一、卷积核与循环核 二、循环核 1.循环核引入 2.循环核:循环核按时间步展开。 3.循环计算层:向输出方向生长。 4.TF描述循环计算层 三、TF描述循环计算 四、RNN使用案例 1.数据集准备 2.Sequential中RNN 3.存储模型,acc和lose…...

安防视频监控/视频集中存储/云存储平台EasyCVR无法播放HLS协议该如何解决?
视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、…...

Docker技术--Docker的安装
1..Docker的安装方式介绍 Docker官方提供了三种方式可以实现Docker环境的安装。分别为:Script、yum、rpm。在实际的环境中建议使用yum或者是rpm。 2..Docker的yum安装 # 1.下载docker wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.re…...

客户案例|MemFire Cloud助推应急管理业务,打造百万级数据可视化大屏
「导语」 硬石科技,成立于2018年,总部位于武汉,是一家专注于应急管理行业和物联感知预警算法模型的技术核心的物联网产品和解决方案提供商。硬石科技作为一家高新技术企业,持有6项发明专利,拥有100余项各类平台认证和资…...

蒲公英路由器如何设置远程打印?
现如今,打印机已经是企业日常办公中必不可少的设备,无论何时何地,总有需要用到打印的地方,包括资料文件、统计报表等等。 但若人在外地或分公司,有文件急需通过总部的打印机进行打印时,由于不在同一物理网络…...

国产自主可控C++工业软件可视化图形架构源码
关于国产自主代替的问题是当前热点,尤其是工业软件领域。 “一个功能强大的全自主C跨平台图形可视化架构对开发自主可控工业基础软件至关重要!” 作为全球领先的C工业基础图形可视化软件提供商,UCanCode软件有自己的思考,我们认…...

【linux命令讲解大全】022.网络管理工具和命令概述
文章目录 lsattr命令语法选项参数实例 nmcli补充说明语法选项OPTIONSOBJECT 实例 systemctl补充说明任务 旧指令 新指令 实例 开启防火墙22端口 从零学 python lsattr命令 用于查看文件的第二扩展文件系统属性。 语法 lsattr(选项)(参数) 选项 -E:可显示设备属…...

应急响应流程及思路
应急响应流程及思路 一:前言 对于还没有在项目中真正接触、参与过应急响应的同学来说,“应急响应”这四个字见的最多的就是建筑工地上的横幅 —— 人人懂应急,人人会响应。这里的应急响应和我们网络安全中的应急响应有着某种本质的相似&…...

网页自适应
自适应 那就要最好提前商量好 是全局自适应 或者是 局部自适应 一般网站页面纵向滚动条都是无法避免的 都是做横向适配也就是宽度 那就不能写死宽度像素 局部自适应 一般对父元素设置百分比就行 里面的子元素就设置固定像素、 比如一些登录 全局自适应 也就是要对每个元素…...

什么是Sui Kiosk,它可以做什么,如何赋能创作者?
创作者和IP持有者需要一些工具帮助他们在区块链上实现其商业模式。Sui Kiosk作为Sui上的一种原语可以满足这种需求,为创作者提供动态选项,使他们能够在任何交易场景中设置完成交易的条件。 本文将向您介绍为什么要在SuiFrens中使用Sui Kiosk,…...

【MySQL】mysql connect
目录 一、准备工作 1、创建mysql用户 2、删除用户 3、修改用户密码 3.1、自己改自己密码 3.2、root用户修改指定用户的密码 4、数据库的权限 4.1、给用户授权 4.2、回收权限 二、连接mysql client 1、安装mysql客户端库 2、验证是否引入成功 三、 mysql接口 1、初…...

基于 vue2 发布 npm包
背景:组件化开发需要,走了一遍发布npm包的过程,采用很简单的模式实现包的发布流程,记录如下。 项目参考:基于vue的时间播放器组件,并发布到npm_timeplay.js_xmy_wh的博客-CSDN博客 1、项目初始化 首先&a…...

基于Axios完成前后端分离项目数据交互
一、安装Axios npm i axios -S 封装一个请求工具:request.js import axios from axios// 创建可一个新的axios对象 const request axios.create({baseURL: http://localhost:9090, // 后端的接口地址 ip:porttimeout: 30000 })// request 拦截器 // 可以自请求…...

时序预测 | MATLAB实现基于PSO-BiLSTM、BiLSTM时间序列预测对比
时序预测 | MATLAB实现基于PSO-BiLSTM、BiLSTM时间序列预测对比 目录 时序预测 | MATLAB实现基于PSO-BiLSTM、BiLSTM时间序列预测对比效果一览基本描述程序设计参考资料 效果一览 基本描述 MATLAB实现基于PSO-BiLSTM、BiLSTM时间序列预测对比。 1.Matlab实现PSO-BiLSTM和BiLSTM…...

C# 生成唯一ID
1.首先通过nuget安装yitter.idgenerator 下面的三行代码搞定...

python怎么提取视频中的音频
目录 操作步骤 1. 安装MoviePy库: 2. 导入MoviePy库和所需的模块: 3. 提取音频: 可能遇到的问题 1. 编解码器支持: 2. 依赖项安装: 3. 文件路径问题: 4. 内存消耗: 5. 输出文件大小&a…...

学习设计模式之建造者模式,但是宝可梦
前言 作者在准备秋招中,学习设计模式,做点小笔记,用宝可梦为场景举例,有错误欢迎指出。 建造者模式 建造者模式是一种创建型模式,主要针对于某一个类有特别繁杂的属性,并且这些属性中有部分不是必须的。…...

数学建模:变异系数法
🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 变异系数法 变异系数法的设计原理是: 若某项指标的数值差异较大,能明确区分开各被评价对象,说明该指标的分辨信息丰富,因而应给该指标以较大的权重…...

paddle.load与pandas.read_pickle的速度对比(分别在有gpu 何无gpu 对比)
有GPU 平台 测试通用代码 import time import paddle import pandas as pd# 测试paddle.load start_time time.time() paddle_data paddle.load(long_attention_model) end_time time.time() print(f"Paddle load time: {end_time - start_time} seconds")# 测试…...

探讨uniapp的路由与页面栈及参数传递问题
1首先引入页面栈 框架以栈的形式管理当前所有页面, 当发生路由切换的时候,页面栈的表现如下: 页面的路由操作无非:初始化、打开新页面、页面重定向、页面返回、tab切换、重加载。 2页面路由 uni-app 有两种页面路由跳转方式&am…...

字节一面:你能讲一下跨域吗
前言 最近博主在字节面试中遇到这样一个面试题,这个问题也是前端面试的高频问题,作为一名前端开发工程师,我们日常开发中与后端联调时一定会遇到跨域的问题,只有处理好了跨域才能够与后端交互完成需求,所以深入学习跨域…...

leetcode 563.二叉树的坡度
⭐️ 题目描述 🌟 leetcode链接:https://leetcode.cn/problems/binary-tree-tilt/description/ 代码: class Solution { public:int childFind(TreeNode* root , int& sumTile) {if (root nullptr) {return 0; // 空树坡度为0}int l…...

【第1章 数据结构概述】
目录 一. 基本概念 1. 数据、数据元素、数据对象 2. 数据结构 二. 数据结构的分类 1. 数据的逻辑结构可分为两大类:a. 线性结构;b. 非线性结构 2. 数据的存储结构取决于四种基本的存储方法:顺序存储、链接存储、索引存储、散列存储 3. …...

【附安装包】MyEclipse2019安装教程
软件下载 软件:MyEclipse版本:2019语言:简体中文大小:1.86G安装环境:Win11/Win10/Win8/Win7硬件要求:CPU2.5GHz 内存4G(或更高)下载通道①百度网盘丨下载链接:https://pan.baidu.co…...

poi-tl设置图片(通过word模板替换关键字,然后转pdf文件并下载)
选中图片右击 选择设置图片格式 例如word模板 maven依赖 <!-- java 读取word文件里面的加颜色的字体 转pdf 使用 --><dependency><groupId> e-iceblue </groupId><artifactId>spire.doc.free</artifactId><version>3.9.0</ver…...