系统架构主题之九:软件设计模式及其应用

1 关于设计模式

设计模式是什么?个人理解,其是软件开发中对一些通用问题整理的解决方案,是经过经验总结所提炼的相对较为抽象的,有一定适应性和变化性的“套路”。这里借用了“套路”这个不太好听的词,但目的却是为了避坑。

关于设计模式经典的著作就是称为GOF的四人组所编写的那本Design patterns。多说两句,关于设计模式,个人有两点看法:其一,现代软件系统设计的越来越庞大复杂,能够用简单的概念和方法解决问题,反而是一种本领。这样一来,软件的可维护性和健壮性将得到大大提升。如果有一天,人工智能发展到绝顶聪明的程度,不再需要人类编写维护软件时,这一条观点就可以过时了,但是现在还远远未到这个要求,所以这一点还是要奉为圭臬。很多一线大佬都指出,哪些复杂无比,充斥不必要技巧的代码,往往是对问题没有彻底理解清楚的产物,对于这一点,我是比较认可的。回到设计模式,我觉得书中所体现的思想是值得学习的,而具体各个模式的方法,反而是要避免复杂化的。形式大于内容并不可取,容易走向花架子方向,偏离本质。反倒是有一些简单的介绍这些模式的书籍,倒是比较推荐的,像大话设计模式。其二,当你学完所有的模式后,不知道是否有这样一种感觉,就是所有模式其实都是围绕着一个中心点在反复咀嚼,这个中心点就是抽象。如果一个人把抽象掌握的熟透,并在实际开发中加以应用,回过头来,你会发现,他或多或少都是采用了某个设计模式,或者说有某个模式的影子。可能并不完全一致,但是其却有相通的妙处。

运用抽象的好处,我在发布的其他博文里也有提及并加以反复强调,这里再提提。抽象最大的好处,就是本质不变特性。这一特性应用于软件开发,特别适合应对变化。因为变化是软件开发的最大绊脚石。有了这一法宝,当然,前提是拿捏的好,运用的秒,就可以做到以不变应万变。关于抽象,这里就说这么多,不再展开。

博主第一次接触到大量运用设计模式的代码是Android的源码。对于初学者而言,是不错的学习资料。在了解了设计模式的概念后,遇到实际的代码,要多想想,为啥采用这种模式,有什么好处。多思考,才能有收获。

2 设计模式本身的概念:

设计模式被分为三大类型,分别是创建型、结构型以及行为型。我是比较讨厌这种分类的,因为官方的分类方法和我自己的理解总感觉有出入,这样在拿出来要用的时候,就比较痛苦,需要一些背诵记忆的能力。这种感觉跟中学学政治一样,不知道是不是因为自己语文太差,对一些文字的含义理解不到位而导致了这种错觉。既然官方按这种方式分类了,记住就好,实在觉得别扭,就找一些比较容易理解的能够往官方分类方向靠的例子来辅助记忆。

具体的分类如下:

创建型包括工厂模式、抽象工厂模式、单例模式、构建者模式、原型模式

结构型模式包括桥接模式、适配器模式、组合模式、代理模式、享元模式、装饰模式、外观模式

行为型模式包括职责链、策略模式、迭代模式、命令模式、状态模式、观察者模式、解释器模式、中介模式、访问者模式、模板方法、备忘录模式

关于这些模式的具体说明,这里就不再展开了,网络的资料十分丰富。虽然GoF提炼了23种模式,但是实际中,常见的模式就那么几种,没必要死扣每一种,而且不用的那些,时间长了也就会遗忘,所以大概了解即可,达到给个选择题能够分辨出来的程度即可。

3 设计模式在系统中的应用和体现

对于设计模式,学以致用才是关键。能够在了解-理解-掌握-运用的链条上达到最终的自如运用,才说明内化于心了。下面,仍然以前述某电力系统项目为例,谈谈在项目中对设计模式的运用。

首先是适配器模式。这是很常见的一种设计模式,多应用于数据匹配上。在该电力系统项目中,也是做数据适配这一目的,但是细节上又有所不同。项目中,围绕会商功能开展了诸多业务,这些业务关联了诸多数据,如何有效、高效管理这些数据,就是设计上的一项小挑战了。比如,除了常见的音频、视频数据外,还有各种采集的电压、电流、温度、定位、图像、短信等各种业务数据。为了有效的管理这些数据,系统设计时,对数据进行了抽象,将其分解为两类数据,一种是流类数据,一种是包类数据,是不是有点类似TCP和UDP。确实,单从抽象概念上讲,是挺像的。每一类数据都有一个源与其关联,而所有的源都来自一个统一的抽象,这样当某个功能或业务需要数据时,就将其对接到抽象源上,也就是适配到统一的适配器上,而具体每一个数据源的处理,又根据其不同的特点,就自己独特的实现。这样,既满足了抽象的统一,有实现了个体的独立,后续有新的业务或数据需要适配时,也仍然走一套统一的抽象对接流程和具体的实现范式,不对整体系统的设计构成冲击,又满足了变化的需求,可谓一石二鸟。

从这个例子中,我们可以再次感受到前面所提的模式和抽象的关系。

其次,观察者模式。这也是非常非常常见的一个模式,特别是应对有回调处理的一类事务时。比如,像界面相关的处理,通用组件的一些处理(按钮响应、列表滚动选择等等),大都会用到这一模式。在该电力系统项目中,也是大量使用了观察者模式。首先是有关数据采集的部分,底层基于异步事件,构建了一个统一的框架,而每一类事件的数据响应,就是通过观察者模式对接到界面应用的,这包括了电压电流数据、GPS定位数据、电源管理数据、按键数据、WIFI事件、对讲事件等等。另外,对于音视频的处理也是采用类似的方法。底层首先设计了一套管线,用于完成音视频数据的采集、编码、传输、接收、解码、渲染等过程。但是,在这条管线上,还有许多关联业务需要处理,此时观察者模式就派上用处了。比如,满足特定条件时进行音视频的截取录制、混音降噪等处理,通过观察者模式实现数据的分流,在基本业务特性不受影响的前提下,可插入丰富的定制业务功能,实现主线和分支的统一管理,协同工作。

第三,模板方法模式。该模式的使用有点类似Android的activity抽象。在工单业务流上,采用统一的任务处理模板,基于抽象的任务模式,定制实现独特的各种子类业务功能,是不是又感受到了抽象的魔力。而且,界面的功能处理,也是采用了统一的生命周期模板,业务界面回到前台,退出前台,运行退出运行,都是该模式的体现。升级和文件的上传下载,也采用了统一的进度模板,只需要传递总量数据和当前片长即可。另外,终端部分的驱动,也是运用模板方法的生动体现。整个框架分为了初始化、读写、中断、去初始化等几个块,这样一来,将抽象和复用利用到了极点。抽象方便了复用,而复用,又促进了抽象,很多时候抽象并不是一开始就想象出来的,而是在开发过程中通过对共性的提炼总结,最终自然而然的就会形成抽象的雏形。

第四,状态模式。状态模式是对传统C语言中状态机的等价表示。客户端自身也是有状态的,比如登录、加入会商、在线、离线等,这些逻辑的处理,就是状态模式发挥作用的地方。另外,网络库部分,也是状态模式抽象的重点。连接、断开的高效管理,不仅简化了业务层面的开发,也使得整个代码更加易读,减少了错误,提高了效率,增强了可靠性,一举多得。

最后,还有其他一些模式的使用,比如代理模式,跨进程的接口代理,做测试桩,都是大量使用的。单例模式,一个时刻一台终端保持一个客户端,就用单例实现。全局统一的消息队列,也用单例,方便获取使用,保证了异步安全性。工厂模式,用于创建各种实例,特别是经典的数据库实例场景,通过工厂模式,统一支持不同数据库产品,不再为切换不同厂家数据库产品而改系统代码。

  关于设计模式在实际系统中的应用就整理这么多。很多时候,我们并不是刻意去选择使用哪种模式(除非是一些非常常见的经典的场景,有现成可用的模式模板可以顺手拿来就用),而是先充分理解功能,理解业务本身,然后考虑各种可能和变化,在这个过程中尽可能的提炼,得到抽象物,之后再将抽象应用于设计实现,在这一整套思考并实践的过程中,你会发现,某些设计模式会自然而然的被应用于系统中,反倒是那些刻意为之的模式,往往最后给人一种别别扭扭的感觉,难以重构或者问题频出。其实,生活中的其他领域也是如此,体现本质的设计,往往更有生命力,而那些流于花哨形式的设计往往得不偿失。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/138025.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++动态库

C动态库 动态库文件(Dynamic Link Library,DLL)是程序在运行时所需要调用的库。静态库文件是程序在编译时所需要调用的库。 1 环境介绍 VS版本:VS2017 编程语言:C 2 功能介绍 使用VS2017项目模板创建C动态库生成…

Java 之 IO/NIO/OKIO

BIO blocking io AIO Asynchronous IO 从内存读取到写入--输出 从外部到内存 -- 输入 OutputStream //文件不存在则自动创建 try {OutputStream outputStream new FileOutputStream("text.txt");outputStream.write(a);outputStream.write(b);} catch (IOExcep…

Java-多态

1. 多态 1.1 多态的概念 多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 1.2 多态实现条件 在java中要实现多态,必须要满足如下几个条件,缺一不…

vivado时序分析-3时序分析关键概念

1、时钟相移 时钟相移对应于延迟时钟波形 , 此波形与因时钟路径内的特殊硬件所导致的参考时钟相关。在 AMD FPGA 中 , 时钟相移通常是由 MMCM 或 PLL 原语引入的 , 前提是这些原语的输出时钟属性 CLKOUT*_PHASE 为非零值。 时序分析期间…

Linux 基于 LVM 逻辑卷的磁盘管理【简明教程】

一、传统磁盘管理的弊端 传统的磁盘管理:使用MBR先对硬盘分区,然后对分区进行文件系统的格式化最后再将该分区挂载上去。 传统的磁盘管理当分区没有空间使用进行扩展时,操作比较麻烦。分区使用空间已经满了,不再够用了&#xff…

如何使用HadSky搭配内网穿透工具打造个人站点并公网访问

🌈个人主页:聆风吟 🔥系列专栏:Cpolar杂谈、数据结构、算法模板 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 前言一. 网站搭建1.1 网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 二. 本地网页发…

可变类与不可变类

可变类(Mutable Class)和不可变类(Immutable Class)是面向对象编程中的两种类的设计模式,它们在对象的状态和行为上有不同的特性。 可变类(Mutable Class): 状态可修改:…

30基于Feign远程调用

2.1.Feign替代RestTemplate Fegin的使用步骤如下&#xff1a; 1&#xff09;引入依赖 我们在order-service服务的pom文件中引入feign的依赖&#xff1a; <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-start…

【算法 | 模拟No.4】AcWing 756. 蛇形矩阵 AcWing 40. 顺时针打印矩阵

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【AcWing算法提高学习专栏】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&a…

【chat】4: ubuntu20.04:数据库创建:mysql8 导入5.7表

【chat】3: ubutnu 安装mysql-8 并支持远程访问 已经支持 8.0的SQLyog 远程访问:大神2021年的文章:sql是5.7的版本,我使用的ubuntu20.04,8.0版本:chat数据库设计 C++搭建集群聊天室(七):MySQL数据库配置 及项目工程目录配置 User表,以id 唯一标识 Friend 表,自己的id…

前后端跨域/ 同时运行两个项目

&#xff08;1&#xff09;后端配置端口 server:port: 90 &#xff08;2&#xff09;前端 配置跨域资源共享&#xff08;CORS&#xff09; devServer: {disableHostCheck: true,port: 8088,proxy: {/openapi: {target: http://192.168.31.109:90,ws: false,changeOrigin: true…

JavaFX入门和网格布局面板的使用,Dao层交互,舞台与场景切换以及其他控件的使用

网格布局 将整个面板划分为若干个格子 , 每个格子的大小是一样的 , 每个格子中可以放置一个控件&#xff08;布局&#xff09; , 类似于表格的方式。在网格布局 中放入控件的时候 , 还需要指定位置。 GridPane gridPane new GridPane(); 我们将要排出这个布局 , 也就是登陆页…

如何通过命令查看某一文件的内容改动和提交记录

1. 查看最近10条的提交记录 一行显示 git log --oneline -102.查看某一个文件的提交记录 git log --oneline -10 文件路径3.查看某个文件的修改内容 查看某次提交的修改 内容 git show bcd9299 查看某次提交某个文件的修改内容git show bcd9299 文件路径4.对比两次提交内容的…

【STM32】HAL库UART含校验位的串口通信配置BUG避坑

【STM32】HAL库UART含校验位的串口通信配置BUG避坑 文章目录 UART协议校验位HAL库配置含校验位的串口配置BUG避坑附录&#xff1a;Cortex-M架构的SysTick系统定时器精准延时和MCU位带操作SysTick系统定时器精准延时延时函数阻塞延时非阻塞延时 位带操作位带代码位带宏定义总线函…

新生儿夜惊:原因、科普和注意事项

引言&#xff1a; 新生儿夜惊是一种常见的现象&#xff0c;它可能让新父母感到焦虑和不安。夜惊通常表现为婴儿在夜间忽然惊醒、哭闹&#xff0c;并伴随着呼吸急促和肌肉紧张。尽管这在大多数情况下是正常的生理现象&#xff0c;但对于父母来说&#xff0c;了解夜惊的原因和适…

力扣labuladong——一刷day24

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣34. 在排序数组中查找元素的第一个和最后一个位置 前言 一文搞懂二分查找&#xff0c;左闭右闭&#xff0c;或者左闭右开&#xff0c;以及寻找左右边界…

HTML点击链接强制触发下载

常见网页中会有很多点击链接即下载的内容&#xff0c;以下示范一下如何实现 <a href"文件地址" download"下载的文件名字&#xff08;不包括后缀&#xff09;">强制下载</a> 下面举个例子&#xff1a; <a href"./image/test.jpg"…

Mysql配置主从复制-GTID模式

目录 主从复制 主从复制的定义 主从复制的原理 主从复制的优势 主从复制的形式 主从复制的模式 主从复制的类型 GTID模式 GTID的概念 GTID的优势 GTID的原理 GTID的配置 Mysql主服务器 ​编辑 Mysql从服务器 ​编辑 主从复制 主从复制的定义 是指把数据从一个…

java.net.UnknownServiceException: CLEARTEXT communication to 127.0.0.1 not p

解决方案3&#xff08;推荐&#xff09; 在 AndroidManifest.xml —> application节点中增加 <application...android:usesCleartextTraffic"true"... />

缓存与数据库双写一致性几种策略分析

一、背景 在高并发场景中&#xff0c;为防止大量请求直接访问数据库&#xff0c;缓解数据库压力&#xff0c;常用的方式一般会增加缓存层起到缓冲作用&#xff0c;减少数据库压力。引入缓存&#xff0c;就会涉及到缓存与数据库中数据如何保持一致性问题&#xff0c;本文将对几…