软件常见设计模式

设计模式

设计模式是为了解决在软件开发过程中遇到的某些问题而形成的思想。同一场景有多种设计模式可以应用,不同的模式有各自的优缺点,开发者可以基于自身需求选择合适的设计模式,去解决相应的工程难题。

良好的软件设计和架构,可以让代码具备良好的可读性、可维护性、可扩展性、可复用性,让整个系统具备较强的鲁棒性和性能,减少屎山代码出现的概率。


创建型模式

创建型设计模式提供了各种对象创建机制,增加了现有代码的灵活性和重用性。

工厂方法模式(Factory Method):为超类提供了一个创建对象的接口,但允许子类改变将被创建的对象的类型。

优点:

  • 良好的封装性。将产品的实例化封装执行,避免被修改,这样的产品具备良好的一致性。
  • 良好的扩展性。增加产品时,同步增加一个工厂子类,不会违反开闭原则。
  • 标准的解耦合框架。使用者只需要知道自己要什么产品即可,不用去管产品具体的特性等等,降低了模块间的耦合。

缺点:

  • 代码量大。每加一个产品,都要加一个工厂子类,代码会显得臃肿。
  • 不利于扩展复杂的产品结构。


抽象工厂模式(Abstract Factory):允许您在不指定具体类的情况下生成一组相关对象的模式,相当于升级版的工厂模式。

优点:

  • 具体类分离。具体产品类在具体工厂的实现中进行了分离和归类。
  • 易于更换产品族。当客户想要改变整个产品族时,只需要切换具体工厂即可。
  • 利于产品一致性。当产品族的各个产品需要在一起执行时,抽象工厂可以确保客户只操作同系列产品,而不会进行跨品牌的组合。

缺点:

  • 不利于添加新种类产品。每加一个新的种类,如多一个项链类型的产品,那每一个具体工厂都要进行代码的扩展,且破坏了原先规定的结构,违反了开闭原则。


建造者模式(Builder):允许您逐步构建复杂对象的模式。该模式允许您使用相同的构建代码生成不同类型和表示的对象。

优点:

  • 封装性好。有效地封装了建造过程(主要业务逻辑),使得系统整体的稳定性得到了一定保证。
  • 解耦。产品本身和建造过程解耦,相同的建造过程可以创建出不同的产品。
  • 产品建造过程精细化。该模式注重产品创建的整个过程,将复杂的步骤拆解得到多个相对简单的步骤,使得系统流程更清晰,且对细节的把控更精准。
  • 易于扩展。如果有新产品需求,只需要添加一个建造者类即可,不需要改动之前的代码,符合开闭原则。

缺点:

  • 产品的组成部分和构建过程要一致,限制了产品的多样性。
  • 若产品内部有结构上的变化,则整个系统都要进行大改,增加了后期维护成本。


原型模式(Prototype):允许您复制现有对象而不使您的代码依赖于它们的类的模式。

优点:

  • 便捷、简洁、高效。不需要考虑对象的复杂程度,只需要复制即可。
  • 无需初始化。可动态地获取当前原型的状态,并在当前基础上进行拷贝。
  • 允许动态增加或减少产品类。

缺点:

  • 每个类都需要配备一个clone函数,若对已有的类进行改造,需要修改其源码,违背了开闭原则。


单例模式(Singleton):单例模式是一种创建型的软件设计模式,在工程项目中非常常见。通过单例模式的设计,使得创建的类在当前进程中只有一个实例,并提供一个全局性的访问点,这样可以规避因频繁创建对象而导致的内存飙升情况。


结构型设计模式

结构型设计模式解释了如何将对象和类组合成更大的结构,同时保持这些结构的灵活性和高效性。

适配器模式(Adapter):允许具有不兼容接口的对象进行协作的模式。

优点:

  • 良好封装性。接口内的内容对使用者而言是透明的,即看不见,这确保了内部功能具备较好的封装性,不易被改动。
  • 解耦。不匹配的两方在适配器的作用下可以做到解耦,不需要修改任何一方原有代码逻辑。
  • 良好复用性。适配的两方不需要做任何修改,业务的实现可以通过适配器来完成,不同的业务可以使用不同的适配器。
  • 良好扩展性。若要增加业务场景,只需要增加适配器类,来满足业务即可。

缺点:

  • 不利于维护。因为业务的实现基于适配器完成,适配器中代码的复杂程度会越来越高,不熟悉业务或者底层逻辑的人难以短时间内接手维护。
  • 系统结构易混乱。当业务量快速增加时,适配器类的数量也会快速增加,没有良好的系统架构布局,最终会使得整个系统臃肿且危险。


桥接模式(Bridge):将一个大类或一组紧密相关的类分割成两个独立的层次结构(抽象和实现),使它们可以相互独立地进行开发的模式。

优点:

  • 扩展性好。抽象与实现分离,扩展起来更便捷,可以获得更多样式的目标。
  • 解耦。不同抽象间的耦合程度低。
  • 满足设计模式要求的合成复用原则和开闭原则。
  • 封装性好。具体实现细节对客户而言是透明不可见的。

缺点:

  • 使用场景有限制。只有系统有两个以上独立变化维度时才适用。


复合模式(Composite):将对象组合成树状结构,然后以与单个对象相同的方式处理这些结构的模式。

优点:

  1. 层次鲜明。凸显“部分-整体”的层次结构。
  2. 一致性。对叶子对象(单)和容器对象(组合)的操作具备良好一致性。
  3. 节点自由度高。在结构中按需自由添加节点。

缺点:

  1. 设计更抽象。
  2. 应用场景限制。


装饰器模式(Decorator):将具有特定行为的对象放置在包含这些行为的特殊包装对象中,从而使您可以向对象附加新的行为的模式。

优点:

  • 灵活性好。相比较继承,装饰模式扩展对象功能更加灵活。
  • 扩展性好。不同装饰组合,可以创造出各式各样的对象,且避免了类爆炸。
  • 满足设计模式要求的开闭原则和合成复用原则。
  • 透明性好。客户端针对抽象操作,对具体实现的内容不可见。

缺点:

  • 复杂性高。装饰模式的设计往往具备较高复杂度,对开发者的水平要求高。
     


外观模式(Facade):为库、框架或任何其他复杂的类集合提供简化的接口的模式。

优点:

  • 简洁易使用。为复杂的模块和系统提供了一个简单的接口,简易化操作。
  • 保证了子系统独立性。子系统间独立性良好,彼此间一般不受影响,如何使用由门面决定。
  • 保证了系统稳定性。当直接使用子系统,可能会出现无法预知的异常时,门面模式可通过高层接口规范子系统接口的调用,且有效阻隔子系统和客户端间的交互,进而增强系统鲁棒性。
  • 隐秘性好。门面将子系统的具体细节都封装了起来。

缺点:

  • 不符合开闭原则。添加新系统要对门面进行修改。
  • 对开发者要求高。开发者需要了解子系统间的业务逻辑关系,这样才能确保封装的高层接口是有效且稳定的。


享元模式(Flyweight):通过在多个对象之间共享状态的公共部分,而不是在每个对象中保留所有数据,可以将更多对象适应可用的内存量的模式。

优点:

  1. 减少资源浪费。共享资源极大程度降低了系统的资源消耗。
  2. 提高系统运行效率。当资源过度使用时,系统效率会大受影响。

缺点:

  1. 维护共享对象,需要额外开销。
  2. 系统复杂度提高。运行享元,除了内外状态,还有线程方面都要充分考虑。


代理模式(Proxy):提供另一个对象的替代或占位符的模式。代理控制对原始对象的访问,允许您在请求传递到原始对象之前或之后执行某些操作。

优点:

  • 职责清晰。真实对象专注于自身业务逻辑,不用考虑其他非本职内容,交给代理完成。
  • 高拓展性。真实对象的改变不影响代理。
  • 解耦。将客户端与真实对象分离,降低系统耦合度。
  • 提高性能。虚拟代理可以减少系统资源的消耗。
  • 高安全性和稳定性。代理能很好地控制访问,提高程序安全。

缺点:

  • 增加系统复杂度。代理的职责往往较冗杂。
  • 请求速度降低。客户端与真实对象中加入代理,一定程度上会降低整个系统流程的运行效率。

行为型设计模式

行为型设计模式关注算法和对象之间责任的分配。

责任链模式(Chain of Responsibility):允许你将请求沿着一条处理器链传递。每个处理器在接收到请求后决定是处理该请求还是将其传递给链中的下一个处理器。

优点:

  • 请求者和接收者松耦合。请求者只需要发送请求,不关心由谁处理怎么处理;接收者只需要处理自己该处理的,剩下的交给责任链上的其他职责处理。
  • 比较灵活。责任链上各个职责对象,可以灵活排序或组合,以应对不同场景。

缺点:

  • 性能易受影响。当责任链过长时,对请求的处理效率不够高。
  • 不一定确保请求完整处理。每个职责只对自身部分负责,有可能请求走完整个责任链,也没有完全处理。


命令模式(Command):将请求转换为独立的对象,该对象包含有关请求的所有信息。通过这种转换,您可以将请求作为方法参数传递、延迟或排队请求的执行,并支持可撤销的操作。


迭代器模式(Iterator):让您遍历集合的元素,而不暴露其底层表示(如列表、堆栈、树等)。

优点:

  • 符合单一职责原则。将遍历行为抽离成单独的类。
  • 符合开闭原则。添加新集合或者新迭代器,不改变原有代码。
  • 便于扩展多种遍历行为。
  • 访问数据又不暴露内部。

缺点:

  • 若对聚合对象只需要进行简单的遍历行为,那使用迭代器模式有些大材小用。
  • 系统复杂性提高,类数量较多。


中介者模式(Mediator):减少对象之间混乱的依赖关系。该模式限制了对象之间的直接通信,并强制它们只能通过中介者对象进行协作。


备忘录模式(Memento):在不透露其实现细节的情况下,保存和恢复对象的先前状态。

优点:

  • 良好封装性。发起人对象中的内部状态被保存在备忘录中,也只能由自己读取,对其他对象起到了屏蔽作用。
  • 提供了状态恢复机制。类似于游戏存档读档。
  • 简化了发起人职责。发起人状态的存储和获取,被分离出去了。

缺点:

  • 资源消耗较大,对发起人对象不同内部状态的存储,会导致开销增加。


观察者模式(Observer):定义订阅机制,以通知多个观察对象有关它们所观察的对象发生的任何事件。


状态模式(State):当对象的内部状态发生变化时,允许对象改变其行为。它看起来就像对象改变了它的类。


策略模式(Strategy):定义一族算法,将每个算法都封装在独立的类中,并使它们的对象可互换使用。


模板方法模式(Template Method):在超类中定义算法的骨架,但允许子类在不改变其结构的情况下覆盖特定的步骤。

优点:

  • 良好复用性。父类中公共部分可以多次使用,具备好的环境适应性。
  • 良好扩展性。子类对父类模板的具体实现作扩展。
  • 符合开闭原则。基于模板扩展功能,不需要改动原有代码。

缺点:

  • 类个数增加。基于模板的每个实现,都要定义一个子类,容易使代码量膨胀。
  • 若父类模板有改动,则子类均要同步更改。


访问者模式(Visitor):将算法与其操作的对象分离开来。

优点:

  • 良好扩展性。扩展对元素的操作,只需要添加访问者。
  • 满足单一职责原则。相关的操作封装为一个访问者,使得访问者职责单一。
  • 解耦。数据结构自身和作用于它的操作解耦合。

缺点:

  • 不易增加元素类。每增加一个元素类,访问者的接口和实现都要进行变化。
  • 违背了依赖倒置原则。访问者依赖的是具体元素而不是抽象元素。
  • 破坏封装。访问者可以获取被访问元素的细节。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vite是什么

vite 是什么 vite —— 一个由 vue 作者尤雨溪开发的 web 开发工具 Vite由两个主要部分组成 dev server:利用浏览器的ESM能力来提供源文件,具有丰富的内置功能并具有高效的HMR生产构建:生产环境利用Rollup来构建代码,提供指令用…

SpringIOC之support模块StaticApplicationContext

博主介绍:✌全网粉丝5W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…

vmware的ubuntu虚拟机因空间满无法启动

正在虚拟机编译android源代码,没注意空间不足,结果回来发现了 Assuming drive cache: write through 的问题,经查是空间不足的原因 按照这个教程,清除出来部分空间,才能进去系统,并且对系统空间做下优化 …

测试总监,让我们用这份《测试用例规范》,再也没加班过

经常看到无论是刚入职场的新人,还是工作了一段时间的老人,都会对编写测试用例感到困扰?例如: 固然,编写一份好的测试用例需要:充分的需求分析能力 理论及经验加持,作为测试职场摸爬打滚的老人…

GitHub热门项目之Memos 打造私有备忘录

效果 1. 写备忘录或简单笔记,支持Markdown 2. 时间线 3. 探索可以看到其他用户公开的内容 项目地址 usememos/memos:一种开源的轻量级笔记服务。轻松捕捉和分享您的伟大想法。 (github.com)https://github.com/usememos/memos 体验地址 Memoshttp://…

2000-2022年各省环境规制数据(原始数据+计算过程+计算结果)

2000-2022年各省环境规制数据(原始数据计算过程计算结果) 1、时间:2000-2022年 2、范围:30省 3、来源:各省年鉴、国家统计局、统计年鉴 4、指标:年份、省份、工业污染源治理投资完成实际额、工业增加值…

基于SpringBoot的教师宿舍管理系统设计与实现(源码+调试)

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于SpringBoot的教师宿…

CapCut - 剪映国际版11.1.0

​【应用名称】:CapCut - 剪映国际版 【适用平台】:#Android 【软件标签】:#CapCut #剪映国际版 【应用版本】:11.1.0 【应用大小】:231MB 【软件说明】:软件升级更新。目前大家广泛使用的最令人惊叹、最专…

【鸿蒙 HarmonyOS 4.0】开发工具安装

一、准备开发环境 1.1、安装IDE 鸿蒙应用开发需要使用配套的IDE——HUAWEI DevEco Studio。 DevEco Studio基于IntelliJ IDEA Community(IDEA社区版)构建,为鸿蒙应用提供了一站式开发环境,集成了开发、运行、调试以及发布应用的…

蓝色证件照怎么改?分享3款实用的证件照工具!

在日常生活和工作中,我们经常需要用到蓝色背景的证件照,无论是求职、办理证件还是其他正式场合,一张高质量的蓝色证件照都是必不可少的。然而,不是每个人都能在照相馆拍出完美的证件照,这时候,一些专业的证…

Socket通信---Python发送数据给C++程序

0. Problems 很多时候实现某种功能,需要在不同进程间发送数据,目前有几种主流的方法,如 让python和C/C程序互相发送数据,其实有几种方法: 共享内存共享文件Socket通信 在这里只提供Socket通信的例程,共享…

不要浪费

解法&#xff1a; 记录一下tle的代码 #include <iostream> #include <vector> #include <algorithm> using namespace std; #define endl \n bool check(vector<int>& a, int l,int k) {int sum 0;for (int i 0; i < a.size() && l…

到底什么是CIDR(无类域间路由)?

【摘要】 CIDR&#xff08;无类域间路由&#xff09;是一种用于对互联网IP地址进行聚合和分配的技术。它通过改变IP地址的分配方式&#xff0c;有效地解决了IPv4地址空间不足的问题。本文将详细介绍CIDR的原理、使用方法以及它对互联网的影响&#xff0c;还会针对CIDR出三道例题…

在vue3中使用canvas实现雨滴效果

在vue3中使用canvas实现雨滴效果 这是封装的一个组件DotAndRain&#xff08; &#xff09; <script setup> import { ref, onMounted } from "vue"; import { onUnmounted } from "vue";let animationFrameId null;const el ref(null); let canv…

Day3 javaweb开发——登录认证

登录功能 没什么好写的&#xff0c;就是LoginController层里面要注入empService的对象 登录校验&#xff08;重点&#xff09; 没有校验的情况 没有登录之前&#xff0c;访问数据的网址需要跳转到登录页面。 http是无状态的&#xff0c;处理其他业务时没有判断他是否登录 …

LINUX读取RTC实时时钟时间

linux 读写RTC时间_linux rtc 读写-CSDN博客

[newstarctf2023] --RE wp

AndroGenshin: rc4加密表&#xff0c;base64换表&#xff1a; 脚本梭就行 python username b"genshinimpact" base64_table [125, 239, 101, 151, 77, 163, 163, 110, 58, 230, 186, 206, 84, 84, 189, 193, 30, 63, 104, 178, 130, 211,164, 94, 75, 16, 32, 33…

anomalib1.0学习纪实-续4:做个小结

我们就以padim为例。 一、主入口&#xff1a; 二、Padim类。 这个Padim类就在src\anomalib\models\image\padim文件夹下。 这个Padim类的父类就是 AnomalyModule&#xff0c;这个父类你不能改动了&#xff0c;里面的内容写死了。 这个Padim类&#xff0c;最重要的是&#xf…

基于Spring Boot的学生评奖评优管理系统,计算机毕业设计(带源码+论文)

源码获取地址&#xff1a; 码呢-一个专注于技术分享的博客平台一个专注于技术分享的博客平台,大家以共同学习,乐于分享,拥抱开源的价值观进行学习交流http://www.xmbiao.cn/resource-details/1760641819451928577

vue 非父子通信-event bus 事件总线

1.作用 非父子组件之间&#xff0c;进行简易消息传递。(复杂场景→ Vuex) 2.步骤 创建一个都能访问的事件总线 &#xff08;空Vue实例&#xff09; import Vue from vue const Bus new Vue() export default Bus A组件&#xff08;接受方&#xff09;&#xff0c;监听Bus的…