系统架构主题之九:软件设计模式及其应用
1 关于设计模式
设计模式是什么?个人理解,其是软件开发中对一些通用问题整理的解决方案,是经过经验总结所提炼的相对较为抽象的,有一定适应性和变化性的“套路”。这里借用了“套路”这个不太好听的词,但目的却是为了避坑。
关于设计模式经典的著作就是称为GOF的四人组所编写的那本Design patterns。多说两句,关于设计模式,个人有两点看法:其一,现代软件系统设计的越来越庞大复杂,能够用简单的概念和方法解决问题,反而是一种本领。这样一来,软件的可维护性和健壮性将得到大大提升。如果有一天,人工智能发展到绝顶聪明的程度,不再需要人类编写维护软件时,这一条观点就可以过时了,但是现在还远远未到这个要求,所以这一点还是要奉为圭臬。很多一线大佬都指出,哪些复杂无比,充斥不必要技巧的代码,往往是对问题没有彻底理解清楚的产物,对于这一点,我是比较认可的。回到设计模式,我觉得书中所体现的思想是值得学习的,而具体各个模式的方法,反而是要避免复杂化的。形式大于内容并不可取,容易走向花架子方向,偏离本质。反倒是有一些简单的介绍这些模式的书籍,倒是比较推荐的,像大话设计模式。其二,当你学完所有的模式后,不知道是否有这样一种感觉,就是所有模式其实都是围绕着一个中心点在反复咀嚼,这个中心点就是抽象。如果一个人把抽象掌握的熟透,并在实际开发中加以应用,回过头来,你会发现,他或多或少都是采用了某个设计模式,或者说有某个模式的影子。可能并不完全一致,但是其却有相通的妙处。
运用抽象的好处,我在发布的其他博文里也有提及并加以反复强调,这里再提提。抽象最大的好处,就是本质不变特性。这一特性应用于软件开发,特别适合应对变化。因为变化是软件开发的最大绊脚石。有了这一法宝,当然,前提是拿捏的好,运用的秒,就可以做到以不变应万变。关于抽象,这里就说这么多,不再展开。
博主第一次接触到大量运用设计模式的代码是Android的源码。对于初学者而言,是不错的学习资料。在了解了设计模式的概念后,遇到实际的代码,要多想想,为啥采用这种模式,有什么好处。多思考,才能有收获。
2 设计模式本身的概念:
设计模式被分为三大类型,分别是创建型、结构型以及行为型。我是比较讨厌这种分类的,因为官方的分类方法和我自己的理解总感觉有出入,这样在拿出来要用的时候,就比较痛苦,需要一些背诵记忆的能力。这种感觉跟中学学政治一样,不知道是不是因为自己语文太差,对一些文字的含义理解不到位而导致了这种错觉。既然官方按这种方式分类了,记住就好,实在觉得别扭,就找一些比较容易理解的能够往官方分类方向靠的例子来辅助记忆。
具体的分类如下:
创建型包括工厂模式、抽象工厂模式、单例模式、构建者模式、原型模式
结构型模式包括桥接模式、适配器模式、组合模式、代理模式、享元模式、装饰模式、外观模式
行为型模式包括职责链、策略模式、迭代模式、命令模式、状态模式、观察者模式、解释器模式、中介模式、访问者模式、模板方法、备忘录模式
关于这些模式的具体说明,这里就不再展开了,网络的资料十分丰富。虽然GoF提炼了23种模式,但是实际中,常见的模式就那么几种,没必要死扣每一种,而且不用的那些,时间长了也就会遗忘,所以大概了解即可,达到给个选择题能够分辨出来的程度即可。
3 设计模式在系统中的应用和体现
对于设计模式,学以致用才是关键。能够在了解-理解-掌握-运用的链条上达到最终的自如运用,才说明内化于心了。下面,仍然以前述某电力系统项目为例,谈谈在项目中对设计模式的运用。
首先是适配器模式。这是很常见的一种设计模式,多应用于数据匹配上。在该电力系统项目中,也是做数据适配这一目的,但是细节上又有所不同。项目中,围绕会商功能开展了诸多业务,这些业务关联了诸多数据,如何有效、高效管理这些数据,就是设计上的一项小挑战了。比如,除了常见的音频、视频数据外,还有各种采集的电压、电流、温度、定位、图像、短信等各种业务数据。为了有效的管理这些数据,系统设计时,对数据进行了抽象,将其分解为两类数据,一种是流类数据,一种是包类数据,是不是有点类似TCP和UDP。确实,单从抽象概念上讲,是挺像的。每一类数据都有一个源与其关联,而所有的源都来自一个统一的抽象,这样当某个功能或业务需要数据时,就将其对接到抽象源上,也就是适配到统一的适配器上,而具体每一个数据源的处理,又根据其不同的特点,就自己独特的实现。这样,既满足了抽象的统一,有实现了个体的独立,后续有新的业务或数据需要适配时,也仍然走一套统一的抽象对接流程和具体的实现范式,不对整体系统的设计构成冲击,又满足了变化的需求,可谓一石二鸟。
从这个例子中,我们可以再次感受到前面所提的模式和抽象的关系。
其次,观察者模式。这也是非常非常常见的一个模式,特别是应对有回调处理的一类事务时。比如,像界面相关的处理,通用组件的一些处理(按钮响应、列表滚动选择等等),大都会用到这一模式。在该电力系统项目中,也是大量使用了观察者模式。首先是有关数据采集的部分,底层基于异步事件,构建了一个统一的框架,而每一类事件的数据响应,就是通过观察者模式对接到界面应用的,这包括了电压电流数据、GPS定位数据、电源管理数据、按键数据、WIFI事件、对讲事件等等。另外,对于音视频的处理也是采用类似的方法。底层首先设计了一套管线,用于完成音视频数据的采集、编码、传输、接收、解码、渲染等过程。但是,在这条管线上,还有许多关联业务需要处理,此时观察者模式就派上用处了。比如,满足特定条件时进行音视频的截取录制、混音降噪等处理,通过观察者模式实现数据的分流,在基本业务特性不受影响的前提下,可插入丰富的定制业务功能,实现主线和分支的统一管理,协同工作。
第三,模板方法模式。该模式的使用有点类似Android的activity抽象。在工单业务流上,采用统一的任务处理模板,基于抽象的任务模式,定制实现独特的各种子类业务功能,是不是又感受到了抽象的魔力。而且,界面的功能处理,也是采用了统一的生命周期模板,业务界面回到前台,退出前台,运行退出运行,都是该模式的体现。升级和文件的上传下载,也采用了统一的进度模板,只需要传递总量数据和当前片长即可。另外,终端部分的驱动,也是运用模板方法的生动体现。整个框架分为了初始化、读写、中断、去初始化等几个块,这样一来,将抽象和复用利用到了极点。抽象方便了复用,而复用,又促进了抽象,很多时候抽象并不是一开始就想象出来的,而是在开发过程中通过对共性的提炼总结,最终自然而然的就会形成抽象的雏形。
第四,状态模式。状态模式是对传统C语言中状态机的等价表示。客户端自身也是有状态的,比如登录、加入会商、在线、离线等,这些逻辑的处理,就是状态模式发挥作用的地方。另外,网络库部分,也是状态模式抽象的重点。连接、断开的高效管理,不仅简化了业务层面的开发,也使得整个代码更加易读,减少了错误,提高了效率,增强了可靠性,一举多得。
最后,还有其他一些模式的使用,比如代理模式,跨进程的接口代理,做测试桩,都是大量使用的。单例模式,一个时刻一台终端保持一个客户端,就用单例实现。全局统一的消息队列,也用单例,方便获取使用,保证了异步安全性。工厂模式,用于创建各种实例,特别是经典的数据库实例场景,通过工厂模式,统一支持不同数据库产品,不再为切换不同厂家数据库产品而改系统代码。
关于设计模式在实际系统中的应用就整理这么多。很多时候,我们并不是刻意去选择使用哪种模式(除非是一些非常常见的经典的场景,有现成可用的模式模板可以顺手拿来就用),而是先充分理解功能,理解业务本身,然后考虑各种可能和变化,在这个过程中尽可能的提炼,得到抽象物,之后再将抽象应用于设计实现,在这一整套思考并实践的过程中,你会发现,某些设计模式会自然而然的被应用于系统中,反倒是那些刻意为之的模式,往往最后给人一种别别扭扭的感觉,难以重构或者问题频出。其实,生活中的其他领域也是如此,体现本质的设计,往往更有生命力,而那些流于花哨形式的设计往往得不偿失。
相关文章:
系统架构主题之九:软件设计模式及其应用
1 关于设计模式 设计模式是什么?个人理解,其是软件开发中对一些通用问题整理的解决方案,是经过经验总结所提炼的相对较为抽象的,有一定适应性和变化性的“套路”。这里借用了“套路”这个不太好听的词,但目的却是为了…...

Spring IoC注解式开发
2023.11.11 注解的存在主要是为了简化XML的配置。Spring6倡导全注解开发。 负责声明Bean的注解,常见的包括四个: ComponentControllerServiceRepository 通过源码可以发现,Controller、Service、Repository这三个注解都是Component注解的别名…...

智能一体化管网水位监测仪怎么样?
城市排水管网是城市正常运行的关键环节,这是地上和地下通道的连接点,一旦出现问题便会影响城市生命线建设的工程进展。在复杂的地下管道内想要了解水位数据,对于政府部门来讲是一个管理难题。如果可以采取智能产品在其中发挥作用,…...

个人网厅——销户
目录 需求文档 公积金销户类 controller层 service层 service层实现类 1.验证 (个人账户) 2.提交(添加) controller层 service层 service层实现类 3.分页查询 controller层 service层 service层实现类 4. 详情查询…...

通过创建自定义标签来扩展HTML
使用HTML时,例如,使用<b>标记显示粗体文本。 如果需要列表,则对每个列表项使用<ul>标记及其子标记<li> 。 标签由浏览器解释,并与CSS一起确定网页内容的显示方式以及部分内容的行为。 有时,仅使用一…...

Nacos热更新
Nacos热更新 相比其他注册中心,Nacos的优势之一在于热更新。 热更新,就是不需要重启服务,就能够更新配置。 nacos配置中心 首先,需要搭建 Nacos,详情见: https://www.cnblogs.com/expiator/p/17392549.h…...
CSS3 中 transition 和 animation 的属性分别有哪些
Transition 属性: transition 属性用于定义元素在状态改变时从一个样式转换到另一个样式的过渡效果。它包含以下几个属性: • transition-property:指定过渡效果应用的 CSS 属性名称,多个属性可以用逗号分隔。 •…...

【狂神说Java】Nginx详解
✅作者简介:CSDN内容合伙人、信息安全专业在校大学生🏆 🔥系列专栏 :狂神说Java 📃新人博主 :欢迎点赞收藏关注,会回访! 💬舞台再大,你不上台,永远…...

【第六章】软件设计师 之 数据结构与算法基础
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 备考资料导航 软考好处:软考的…...

Git基本概念和使用方式
Git 是一种版本控制系统,用于管理文件版本的变化。以下是其基本概念和使用方式: 仓库(repository):Git 存储代码的地方,可以理解为一个项目的文件夹。提交(commit):Git …...
Falcon构建轻量级的REST API服务
Falcon构建轻量级的REST API服务 文章目录 Falcon构建轻量级的REST API服务安装falcon构建falcon项目应用托管(Hosting Your App)简单示例内容服务(Serving Text)JSON请求和响应处理路由和 URI 参数中间件异常处理 图像服务(Serving Images)创建图像资源关联资源请求和响应对象…...

【Python】python读取,显示,保存图像的几种方法
一、PIL:Python Imaging Library(pillow) PIL读取图片不直接返回numpy对象,可以用numpy提供的函数np.array()进行转换,亦可用Image.fromarray()再从numpy对象转换为原来的Image对象,读取,显示&…...

k8s系列-kuboard 该操作平台的使用操作
文章目录 一、相关平台,以及账号和密码镜像打包服务器仓库地址K8s平台数据库mysql 二、平台概述1.集群导入2.集群管理3.名称空间4.访问控制授权5.集群用户操作审计 三、kuboard平台操作手册一、部署服务操作1.名称空间部署2.工作负载部署 一、相关平台,以…...

基于讯飞星火大语言模型开发的智能插件:小策问答
星火大语言模型是一种基于深度学习的自然语言处理技术,它能够理解和生成人类语言。这种模型的训练过程涉及到大量的数据和复杂的算法,但最终的目标是让机器能够像人一样理解和使用语言。 小策问答是一款基于星火大语言模型的定制化GPT插件小工具。它的主…...

笔记:AI量化策略开发流程-基于BigQuant平台(二)
五、模型训练股票预测 完成了数据处理,接下来就可利用平台集成的各算法进行模型训练和模型预测啦。本文将详细介绍“模型训练”、“模型预测”两大模块操作、原理。 模型训练和模型预测是AI策略区别于传统量化策略的核心,我们通过模型训练模块利用训练…...
100127. 给小朋友们分糖果 II
给你两个正整数 n 和 limit 。 请你将 n 颗糖果分给 3 位小朋友,确保没有任何小朋友得到超过 limit 颗糖果,请你返回满足此条件下的 总方案数 。 示例 1: 输入:n 5, limit 2 输出:3 解释:总共有 3 种方…...

【2】Spring Boot 3 项目搭建
目录 【2】Spring Boot 3 初始项目搭建项目生成1. 使用IDEA商业版创建2. 使用官方start脚手架创建 配置与启动Git版本控制 个人主页: 【⭐️个人主页】 需要您的【💖 点赞关注】支持 💯 【2】Spring Boot 3 初始项目搭建 项目生成 1. 使用IDEA商业版创…...

【第七章】软件设计师 之 程序设计语言与语言程序处理程序基础
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 1、前言 正规式 2、编译过程 编译型&…...

如何判断一个角是否大于180度(2)
理论计算见上一篇: 如何判断一个角是否大于180度?_kv1830的博客-CSDN博客 此篇为代码实现 一。直接上代码: import cv2 as cv import numpy as np import mathdef get_vector(p_from, p_to):return p_to[0] - p_from[0], p_to[1] - p_from…...

ASAM OpenDRIVE V1.7协议超详解(一)
文章目录 前言一、仿真场景的构成二、openDRIVE框架三、g_additionalData四、openDRIVE-header五、openDRIVE-road1、Road总拓扑结构2、Road-link介绍1)link的拓扑结构2)link链接示例3)link前继后继4)道路link规则 3、road-type介…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...