当前位置: 首页 > news >正文

设计模式大赏(一):桥接模式,组合模式

设计模式大赏(一):桥接模式,组合模式

在这里插入图片描述

导言

本篇文章是设计模式大赏中的第一篇文章,这个系列的文章中我们主要将介绍一些常见的设计模式,主要是我在看Android源码中发现用到的一些设计模式。本篇文章将主要介绍桥接模式
组合模式 这两种设计模式。

本篇文章主要参考:《大话设计模式》

桥接模式

在这里插入图片描述

Android中的桥接模式

我一开始接触到桥接模式是在学习Android的WindowManager相关的源码过程中,具体来说,WindowManager的实现类WindowManagerImpl实际上并不直接实现相关的请求,而是将其委托给WindowManagerGlobal这个单例类来实现。这样将实现分为抽象和具体两部分的模式就叫做桥接模式

合成/聚合复用原则

在正式介绍到桥接模式之前我们需要先介绍一下合成聚合复用原则,该原则的核心思想就是:尽量使用合成和聚合,而不要去使用类的继承

聚合表示一种弱的拥有关系,即A对象可以包含B对象,但B对象不是A对象的一部分。比如说整个班级中可以包含我们个人,但是我们个人并不是班级的一部分,我们脱离开班级还是可以独立存在的,班级脱离我们也可以独立存在。

合成则表示一种强的拥有关系,比如说鸡翅对于鸡一样,显然鸡翅是鸡的一部分,他们的生命周期是一致的,谁也脱离不开谁。

但无论是聚合还是合成关系,他们的耦合强度都要低于继承,继承是一种强耦合的关系,遵循合成/聚合复用原则可以防止类发展成一个难以管理的庞然大物。

桥接模式的概念

桥接模式(Bridge),是一种将抽象部分与它的实现部分分离,使他们都可以独立变化的一种设计模式。

下面是一个标准的桥接模式的基本模板:
在这里插入图片描述
实际上这样说还是很抽象,我们可以借用大话设计模式中的例子来说明:
比如说对手机来说,我们可以将其拆分出两个抽象的概念:手机的硬件和手机的软件,对于我们Android端来说,各个手机厂商的硬件之间都是高度定制化的,所以我们可以将其简化为手机厂商的品牌和手机的软件这两个抽象:

在这里插入图片描述
显然各个品牌手机的手机都会持有各自的手机软件,但是手机软件并不是属于手机的一部分,这是一种聚合持有的关系。这样分类的原因就是为了方便手机品牌和手机软件之间各自的拓展:即为每个抽象添加功能不涉及到其他类的修改。

实际上,我觉得桥接模式强调的就一点:通过多个角度将一个系统进行切分,使各个部分在变化的时候不影响其他部分的变化。

这样做的好处有:

  1. 使系统更加灵活,能够独立地扩展和变化抽象部分和实现部分。
  2. 提高了系统的可维护性和可扩展性,因为可以通过添加新的抽象或实现类来扩展系统。

桥接模式的具体示例

为了更好地理解,接下来引入一个具体的实例:比如说我们想要生产瓶装饮料的话,就可以将这整个罐装饮料抽象成两个部分:装饮料的瓶子和具体的饮料

在这里插入图片描述
下面是我的示例代码:

fun main() {val Glass:Bottle = GlassBottle(Cola())val Plastic:Bottle = PlasticBottle(Sprite())val Bridge = BottleBridgeImpl()Bridge.LoadDrink(Glass)Bridge.LoadDrink(Plastic)
}
//抽象类-瓶子
abstract class Bottle(var mDrinks:Drinks) {//制作瓶子的方法abstract fun MakeBottle()}
//抽象类-饮料
abstract class Drinks{//生产饮料的方法abstract fun MakeDrinks()
}
//抽象出连接上面两个抽象类的桥接方法
interface BottleBridge{//装瓶的方法fun LoadDrink(bottle:Bottle)
}class BottleBridgeImpl():BottleBridge{override fun LoadDrink(bottle: Bottle) {println("压缩装瓶,倒入${bottle.mDrinks}")}
}class GlassBottle(mDrinks: Drinks):Bottle(mDrinks) {override fun MakeBottle() {println("生产玻璃瓶")}
}class PlasticBottle(mDrinks: Drinks):Bottle(mDrinks) {override fun MakeBottle() {println("生产塑料瓶")}
}class Cola():Drinks(){override fun MakeDrinks() {println("生产可乐")}override fun toString(): String {return "可乐"}
}class Sprite():Drinks() {override fun MakeDrinks() {println("生产雪碧")}override fun toString(): String {return "雪碧"}
}

此处我将饮料和瓶子这两部分抽象出来,并引入了一个连接这两个部分的桥接接口,这样饮料和瓶子这两个抽象概念在变化的过程只需要维护自身的制造方法即可而不需要关注其他部分。

总而言之,我觉得桥接模式的核心就是从多个维度将一个系统进行拆分,抽象出各个抽象部分,然后各个抽象部分各自有自己的实现,使得一个抽象部分的具体实现变化时不影响其他的部分。

组合模式

在这里插入图片描述

组合模式的概念

组合模式,是将对象组合成树形结构以表示整体-部分的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性

这整个描述里有两个关键字:树形结构以及一致性。这里我们可以以一个学校的管理为例,学校的管理系统首先是一个大的全局的学校管理系统,向下细分又可以分为学院管理系统,再向下还可以分为各个专业的管理系统,这整个结构是一个树形的结构;而对于各个层级的管理系统我们肯定希望他们对具体信息的操作是一致的,比如说我们可以在学院管理系统对学生A进行加分操作,也可以在专业管理系统中对学生A进行加分操作,这个加分操作无论是在哪个层级的管理系统中发起的都应该有一致的效果,这就是一致性

下面是组合模式的典型结构图:
在这里插入图片描述

Android中的组合模式

说到这里是不是觉得这个组合模式很像Android中ViewGroup和View的组合关系,实际上确实如此,通过使用组合模式,Android开发人员可以更容易地管理和操作UI元素,以便以可扩展和灵活的方式构建用户界面。每个 ViewGroup 作为容器可以包含多个子 View,从而形成了整个布局的层次结构。
在这里插入图片描述

何时使用组合模式

使用组合模式的最佳场景就是当你发现需求中体现的是整体与部分层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,此时就应该考虑使用组合模式了,在上面说到了Android整个视图层次就是用到了组合模式,实际上Java上的UI层次也类似。

这个组合模式如果理解了Android中View的视图层次应该就很形象了,此处就不再另加例子,大家可以去看看Android中View的视图层次。

使用组合模式的好处

使用组合模式的好处,首先我觉得如果体现的是整体与部分的层次结构时,使用组合模式显然可以让整个需求的层次更加清晰

其次,用户不用关心这到底是一个组件组还是一个组件,简单来说组合模式让用户可以一致地使用组合结构和单个对象。

相关文章:

设计模式大赏(一):桥接模式,组合模式

设计模式大赏(一):桥接模式,组合模式 导言 本篇文章是设计模式大赏中的第一篇文章,这个系列的文章中我们主要将介绍一些常见的设计模式,主要是我在看Android源码中发现用到的一些设计模式。本篇文章将主要…...

数据通信——应用层(DHCP的原理与配置)

引言 假如我们的网络中有N台设备,它们都要设置IP地址,如果人工去一个个配置不仅不方便管理还很麻烦。因此我们用DHCP来自动分配地址。 一,系统的启动流程 不仅是计算机、很多网络设备的启动流程如下: 设备上电后,硬件…...

力扣151.反转字符串中的单词

原题链接&#xff1a;力扣151.反转字符串中的单词 全代码&#xff1a; 需要复刷 class Solution { public:void reverse(string& s, int start, int end){ //翻转&#xff0c;区间写法&#xff1a;左闭右闭 []for (int i start, j end; i < j; i, j--) {swap(s[i],…...

vim三种模式,文本操作(操作字符/光标,列出行号可视化块模式/多文件查看)

目录 vim--文本编辑器 功能 基本概念 命令/默认模式 插入模式 底行模式 文本操作 引入 移动光标位置 删除字符 -- x/dd 复制/粘贴字符 -- yw/yyp 替换文本 -- r / %s 底行模式 全局替换 -- /g 撤销操作 -- u / ctrlr 修改字符 -- cw 示例 跳行 -- ctrlg 底行…...

jquery控制easyui中combobox、textbox显示隐藏

//combobox下拉框 $("#下拉框id.combo").hide();//textbox输入框 $("#输入框id.textbox").hide(); 参考网址&#xff1a; https://blog.csdn.net/Coldmood/article/details/128279727...

Android拖放startDragAndDrop拖拽onDrawShadow静态添加xml布局View,Kotlin(4)

Android拖放startDragAndDrop拖拽onDrawShadow静态添加xml布局View&#xff0c;Kotlin&#xff08;4&#xff09; import android.content.ClipData import android.graphics.Canvas import android.graphics.Point import android.os.Bundle import android.util.Log import a…...

Servlet 初始化参数(web.xml和@WebServlet)

1、通过web.xml方式 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://xmlns.jcp.org/xm…...

shell_62.shell脚本生成一个标准的 SQL INSERT 语句

无论是将文件读入脚本&#xff0c;还是将数据从脚本输出到文件&#xff0c;都会用到文件重定向&#xff0c;这是一种很 常见的操作。本节中的示例脚本两种功能皆有。它会读取 CSV 格式的数据文件&#xff0c;输出 SQL INSERT 语句&#xff0c;并将数据插入数据库。 shell 脚本使…...

华为ICT——第五章语音处理理论与实践

目录 语言学&#xff1a; 主要应用场景&#xff1a; 语言学&#xff1a; 语言学&#xff1a; 语音学&#xff08;1&#xff09; 语音学&#xff08;2&#xff09; 语音处理介绍&#xff1a; 人类语音的来源&#xff1a; 语言数据&#xff1a; 语言信号预处理&#xff1a; …...

ardupilot开发 --- SLAM 篇

1. 视觉SLAM 1.1 深度相机的种类 结构光相机&#xff0c;如 Kinect1.0、RealSenseTOF相机&#xff0c;如 Kinect2.0双目相机&#xff0c;如 ZED详细参考&#xff1a;https://zhuanlan.zhihu.com/p/282776636 1.2 视觉SLAM算法 2D slam 与3D slam 应用场景有哪些不同&#x…...

Elasticsearch:在你的数据上训练大型语言模型 (LLM)

过去的一两年&#xff0c;大型语言模型&#xff08;LLM&#xff09;席卷了互联网。 最近 Google 推出的 PaLM 2 和 OpenAI 推出的 GPT 4激发了企业的想象力。 跨领域构思了许多潜在的用例。 多语言客户支持、代码生成、内容创建和高级聊天机器人都是一些例子。 这些用例要求 LL…...

拓展卡尔曼滤波EKF

How to fusion two Gauss Distribution N ( x , μ 0 , σ 0 ) N ( x , μ 1 , σ 1 ) N ( x , μ ′ , σ ′ ) \begin{equation} \begin{aligned} \mathcal{N}(x,\mu_0,\sigma_0) \mathcal{N}(x,\mu_1,\sigma_1) \mathcal{N}(x,\mu,\sigma) \\ \end{aligned} \end{equatio…...

第四章 应用SysML基本特性集的汽车示例 P2(断更)|系统建模语言SysML实用指南学习

仅供个人学习 使用试用版CSM很鸡肋&#xff0c;然后书中一些内容没有说明&#xff0c;自定义方面有点困难&#xff0c;第四章暂时停止 同时感觉画图的顺序也很随意&#xff1f;甚至需求图放在了后面&#xff0c;觉得很离谱。 准备跳过这一章节 汽车模型 续P1 序列图表示启…...

Vue入门——核心知识点

简介 Vue是一套用于构建用户界面的渐进式JS框架。 构建用户界面&#xff1a;就是将后端返回来的数据以不同的形式(例如&#xff1a;列表、按钮等)显示在界面上。渐进式&#xff1a;就是可以按需加载各种库。简单的应用只需要一个核心库即可&#xff0c;复杂的应用可以按照需求…...

使用opencv的tracking模块跟踪目标

OpenCV跟踪模块算法介绍 OpenCV的tracking模块是一个功能强大的跟踪算法库&#xff0c;包含多种用于跟踪对象的算法。它可以帮助你在连续的视频帧中定位一个物体&#xff0c;例如人脸、眼睛、车辆等。 在OpenCV的tracking模块中&#xff0c;一些主要的跟踪算法包括&#xff1…...

Debian或Ubuntu静态交叉编译arm和aarch64

Debian或Ubuntu静态交叉编译arm和aarch64 介绍术语ARM架构前置条件从源代码编译一个简单的C程序configure和make交叉编译关于静态链接和依赖关系使用 musl libc 实现与 configure 和 make 进行交叉编译 ARM 正在获得越来越多的关注&#xff0c;并且越来越受欢迎。直接在这些基于…...

最新ai系统ChatGPT程序源码+详细搭建教程+以图生图+Dall-E2绘画+支持GPT4+Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…...

【设计模式】第16节:行为型模式之“命令模式”

一、简介 命令模式&#xff1a;将请求&#xff08;命令&#xff09;封装为一个对象&#xff0c;这样可以使用不同的请求参数化其他对象&#xff08;将不同请求依赖注入到其他对象&#xff09;&#xff0c;并且能够支持请求&#xff08;命令&#xff09;的排队执行、记录日志、…...

安装pytorch报错torch.cuda.is_available()=false的解决方法

参考文章&#xff1a; https://blog.csdn.net/qq_46126258/article/details/112708781 https://blog.csdn.net/Andy_Luke/article/details/122503884 https://blog.csdn.net/anmin8888/article/details/127910084 https://blog.csdn.net/zcs2632008/article/details/127025294 …...

自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮

自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮 自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮 <template><div class"box"><el-table :data"msgMapList" border class"table">&l…...

光伏电站正在“看不见”地亏钱:峰值报不准、爬坡跟不上、回落抓不住,问题到底出在哪?

关键词&#xff1a; 光伏功率预测、新能源功率预测、电力现货交易、爬坡事件、辐照度预测2026年的春天&#xff0c;光伏电站的运营者们发现了一个越来越尴尬的现象&#xff1a;设备越换越高效&#xff0c;组件越装越密&#xff0c;电表转得越来越快——但月底一算账&#xff0c…...

BilibiliDown:B站视频高效下载的4个核心解决方案

BilibiliDown&#xff1a;B站视频高效下载的4个核心解决方案 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors/bi/Bil…...

WeChatMsg:数据自主权回归的创新方法

WeChatMsg&#xff1a;数据自主权回归的创新方法 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatMsg 副标题…...

Qwen3-TTS-12Hz-1.7B-Base快速部署:基于Jupyter+Gradio的极简开发环境搭建

Qwen3-TTS-12Hz-1.7B-Base快速部署&#xff1a;基于JupyterGradio的极简开发环境搭建 本文介绍如何在JupyterGradio环境中快速部署Qwen3-TTS-12Hz-1.7B-Base语音合成模型&#xff0c;无需复杂配置&#xff0c;10分钟即可实现声音克隆和语音生成功能。 1. 环境准备与快速部署 1…...

Windows 11 LTSC 应用商店安装工具:一键解锁完整应用生态

Windows 11 LTSC 应用商店安装工具&#xff1a;一键解锁完整应用生态 【免费下载链接】LTSC-Add-MicrosoftStore Add Windows Store to Windows 11 24H2 LTSC 项目地址: https://gitcode.com/gh_mirrors/ltscad/LTSC-Add-MicrosoftStore 你是否在使用Windows 11 LTSC版本…...

BMS软件架构实战 — 深入解析Modbus协议栈与通信实现

1. Modbus协议在BMS中的核心价值 电池管理系统&#xff08;BMS&#xff09;作为新能源领域的"大脑"&#xff0c;需要实时监控数百个电芯参数。而Modbus协议就像一位高效的"翻译官"&#xff0c;将复杂的电池数据转化为标准化的通信语言。我在电动汽车BMS项目…...

深入解析TI DSP的Q格式与IQmath库:定点数运算的高效实现

1. 从浮点到定点&#xff1a;为什么需要Q格式&#xff1f; 第一次接触DSP开发时&#xff0c;我发现一个有趣的现象&#xff1a;很多高性能DSP芯片居然不支持硬件浮点运算&#xff01;这就像买了个顶级跑车却发现不能跑高速公路。后来才明白&#xff0c;在嵌入式领域&#xff0c…...

塞尔达传说旷野之息存档编辑器:终极免费工具使用指南 [特殊字符]

塞尔达传说旷野之息存档编辑器&#xff1a;终极免费工具使用指南 &#x1f3ae; 【免费下载链接】BOTW-Save-Editor-GUI A Work in Progress Save Editor for BOTW 项目地址: https://gitcode.com/gh_mirrors/bo/BOTW-Save-Editor-GUI 还在为海拉鲁大陆的冒险资源不足而…...

如何优雅处理Fumadocs错误:打造用户友好的异常捕获与错误页面

如何优雅处理Fumadocs错误&#xff1a;打造用户友好的异常捕获与错误页面 【免费下载链接】fumadocs The beautiful & flexible React.js docs framework. 项目地址: https://gitcode.com/GitHub_Trending/fu/fumadocs 在开发React.js文档网站时&#xff0c;错误处理…...

百台AGV如何协同?揭秘基于树莓派CM5机器人控制器的调度黑科技

在智能仓储的繁忙战场上&#xff0c;AGV&#xff08;自动导引运输车&#xff09;如同不知疲倦的“搬运工”&#xff0c;穿梭于货架之间。但当“搬运工”从几个变成几十个、上百个时&#xff0c;问题就来了&#xff1a;如何让它们井然有序&#xff0c;不堵车、不撞车、不“摸鱼”…...