一文掌握设计模式(定义+UML类图+应用)

news2024/9/23 7:33:37

一、引子

  从学编程一开始就被告知,要想做一名优秀的程序员两大必要技能:1.源码阅读(JDK、C等底层语言封装) 2.设计模式(使用某种语言优雅的落地典型场景功能)。一般随着工作年限的增长,被迫对底层语言/框架源码阅读的越来愈多,但是设计模式如不刻意去学习,永远不会真正掌握。笔者把设计模式比喻成程序员的“绝世神功”,掌握了设计模式,对快速阅读源码、优雅地编写程序有极大的促进作用,可以说就像打通了任督二脉一样。

1.1 设计模式由来

1995年,GoF(Gang of Four四人帮)合作出版了《设计模式:可复用面向对象软件的基础》(Design Patterns – Elements of Reusable Object-Oriented Software) 一书,书中总结了23种面向对象设计模式,也就是大名鼎鼎的GOF设计模式

1.2 23种 VS 24种

一直听说有24种设计模式(网上一大堆标题24种设计模式,然后列举的只有23种,也是无语),公认的GOF只有23种,还有一种是啥?大部分文章都说是简单工厂模式(Simple Factory)。笔者搜遍全网(连chatGPT也问了),没找到第24种设计模式谁提出的。这第24种设计模式,有说是简单工厂模式,也有说是静态工厂模式,也有说简单工厂模式=静态工厂模式,真是一塌糊涂,乱七八糟。神奇的是这些文章的作者都没深究过这个问题,估计大都是拿来主义。

到底几种?

---23种!!!GOF的23种设计模式即可。还有2个模式:简单工厂、静态工厂,确实在后续应用比较多,但在1995年未列入GOF。

二、知识预备

想要练成绝世武功,内功心法和外家套路缺一不可。要想练成“设计模式”这一绝世武功,“面向对象设计原则”就是内功心法(遵循的设计原则),“UML统一建模语言”就是外家套路(代码落地建模工具)。练功之前,咱们先简单学习下这2个必备的基础技能。

2.1 面向对象设计原则

面向对象设计的目标之一就是支持可维护性复用,一方面需要实现设计方案的重用,另一方面要确保系统易于拓展和修改,具有较好的灵活性。7种面向对象设计原则,其中前5条是强约束性的建议都做到,后2条尽量做到即可。

1、单一职责原则(Single Responsibility Principle , SRP):一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。--单一职责原则是实现高内聚低耦合的指导方针。

理解:

  • 一个类只负责一个职责。

2、开闭原则(Open Close Principle):对扩展开放,对修改关闭。--开闭原则是面向对象设计的目标

理解:

  • 使用接口和抽象类。实现不修改原代码,又可以拓展新方法。

3、里氏代换原则(Liskov Substitution Principle):所有引用基类(父类)的地方必须能透明地使用其子类的对象。--里氏代换原则是实现开闭原则的基础

理解:

  • 把父类设计为抽象类或者接口。
  • 子类必须实现父类的所有方法。

4、依赖倒转原则(Dependence Inversion Principle):高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不依赖于细节,细节应该依赖于抽象。--依赖倒转原则就是面向对象设计的主要手段

理解:

  • 要针对接口编程,不要针对实现编程。
  • 依赖注入:将一个类的对象传入另一个类,注入时尽量注入父类对象,程序运行时通过子类对象覆盖父类对象。

5、接口隔离原则(Interface Segregation Principle):客户端不应该依赖那些它不需要的接口(方法),--接口级的单一职责原则

理解:

  • 大接口要分割成小接口,接口专用。
  • 客户端使用专用接口。

6、迪米特法则(Demeter Principle):即最少知道原则,一个实体应当尽量少的与其他实体之间发生相互作用,减少耦合

理解:

  • 依赖者只依赖该依赖的对象,被依赖者只暴露该暴露的对象。

7、合成复用原则(Composite Reuse Principle):尽量使用合成/聚合的方式,而不是使用继承,降低耦合

理解:

  • 少用继承,降低耦合。

2.2 UML建模

UML1.X有9个图,UML2.0有12个图,具体如下图所示:

一般,我们掌握 UML1.X 常用的9种图即可,分为两类:

  • 静态图:用例图、类图、包图、对象图、部署图
  • 动态图:顺序图(时序图),通信图(UML1.x 时称为协作图),状态机图,活动图

本文需要使用静态图的一种:类图。关注类图中类之间的6种关系(耦合度大小排序):泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

2.2.1 类图-关联关系

  • 1.泛化:指的是继承关系,表达一般和特殊。符号:空心三角箭头的实线,箭头指向父类。(注:UML中只有泛化,继承是开发角度的描述。)
  • 2.实现:指的是类与接口的关系,表达类实现了接口的特征行为。符号:带三角箭头的虚线,箭头指向接口。
  • 3.组合:指的是整体与部分的关系, 但部分不能离开整体而单独存在。符号:带实心菱形的实线,菱形指向整体。
  • 4.聚合:指的是整体和部分关系,且部分可以离开整体而单独存。符号:空心菱形的实心线,菱形指向整体。
  • 5.关联:指的是类和类的关系,表达一个类知道另一个类的属性和方法。符号:带普通箭头(或实心三角形箭头)的实心线。
  • 6.依赖:指的是使用的关系, 即一个类的实现需要另一个类的协助, 所以要尽量不使用双向的互相依赖。符号:带箭头的虚线,指向被依赖的类。

2.2.2 类图-表示方法

  • 从上到下分为3部分:类名、属性、方法。
  • 符号含义:+ public、- private、#protected

三、设计模式

本节列举24种设计模式,其中创建型模式6种、结构型模式7种、行为型模式11种。每个模式从3个角度进行分析:定义、UML类图、应用

3.1 创建型模式

创建型模式,就是用来创建对象的。包含3块:单例/原型模式、工厂模式(简单工厂、工厂方法、抽象工厂)、建造者模式。

1.单例模式(Singleton)

定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

UML类图:

 

应用:待补充

2.原型模式(Prototype)

定义:用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

UML类图:

 

3.简单工厂模式(Static Factory Method Pattern)

定义:定义一个工厂类,使用static方法创建对象。根据不同参数返回不同实例,每增加一个对象需要修改工厂类,违背了“开闭原则”。--不推荐使用。

UML类图:

应用:

  • Calendar 类获取日历类对象,static getInstance方法,根据参数获取一个Calendar子类对象。
  • Logback 中的 LoggerFactory日志工厂 ,static getLogger方法根据name/Class获取 Logger 对象。
  • Spring的BeanFactory接口,getBean(),根据name/Class获取不同对象,但不是static修饰的,严格来说不算简单工厂。

4.工厂方法模式(Factory Method)

定义:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。此模式使一个类的实例化延迟到其子类

UML类图:

应用:

  • java.net.URLStreamHandlerFactory作为工厂方法接口,定义了抽象方法createURLStreamHandler创建产品URLStreamHandler。工厂方法实现类为sun.misc.Launcher内部类Factory。

5.抽象工厂模式(Abstract Factory)

定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。用于创建一个产品族的产品。

UML类图:

 

应用:

  • java.sql.Connection接口就是抽象工厂接口,定义了创建Statement产品族:Statement createStatement()、PreparedStatement prepareStatement(String sql)、CallableStatement prepareCall(String sql) 。PgConnection impl BaseConnection(extends Connection)就是一个具体工厂,专用于PostgreSql数据库的连接工厂。PgConnection复写了Statement产品族(3个创建)方法。

6.建造者模式(Builder)

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

UML类图:

 

 应用:

  • 实际应用中,具体建造者Builder一般直接使用静态内部类实现。创建产品时类似:XXX.Builder(参数1,参数2,...).build()。Mybatis源码org.apache.ibatis.builder包下:MapperBuilderAssistant指挥者中,产品有:ParameterMap、ParameterMapping、ResultMap、、ResultMapping、Discriminator、MappedStatement等。每个产品都有自己的建造者静态内部类Builder(定义了build())。

3.2 结构型模式

1.适配器模式(Adapter)

定义:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

UML类图:

应用:

Spring AOP中,org.springframework.aop.framework.adapter包下的AdvisorAdapter接口,有3个适配器实现类:AfterReturningAdviceAdapter、MethodBeforeAdviceAdapter、ThrowsAdviceAdapter把每一个Advisor中的Advice都要适配成对应的MethodInterceptor对象。这里使用的是方式二对象适配器的变种。比如MethodBeforeAdviceAdapter适配器通过getInterceptor()获取到MethodBeforeAdviceInterceptor,最终结合拦截器模式(非GOF23),调用advice的advice.before()实现。

  • 目标接口:AdvisorAdapter接口
  • 适配者:MethodBeforeAdvice接口
  • 适配器:MethodBeforeAdviceAdapter(advisor->advice)+MethodBeforeAdviceInterceptor(把适配者advice做入参构造,最终调用适配者方法执行)

比较复杂,图示如下:

2.桥接模式(Bridge)

定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

UML类图:

拆出一个维度出来,进行聚合,可有效减少子类的个数。原本维度1个数*维度2个数->维度1个数的子类+维度2个数的聚合实现+1个聚合接口

应用:

java.sql包下的DriverConnection接口,通过DriverManager进行桥接(不像图中的聚合实现)。DriverManager定义了registerDriver和getConnection方法。registerDriver可以注册各种驱动。Connection接口可实现连接多种数据库。2个维度分开进行拓展实现,进行了脱耦。

3.组合模式(Composite)

定义:将对象组合成树形结构以表示“部分-整体”的层次结构。它使得客户对单个对象和复合对象的使用具有一致性。

UML类图:

组合模式分为透明式(树枝特有方法在抽象类中体现,树叶类复写空实现,客户端使用时无需区分树枝还是树叶)和安全式(树枝特有方法在树枝类中体现)。当节点具有一致行为时采用透明式,当各节点行为不一致较多或树枝节点较为健壮时采用安全式。

应用:

  • Map接口作为Component容器接口HashMap作为Composite树枝、Node实现了Map接口下的唯一接口Entry<K,V>kv映射实体接口作为Leaf树叶,HashMap有一个属性Node<K,V>[] table链表首歌节点组成的数组,可理解为聚合了Map接口。HashMap复写putAll(Map<? extends K, ? extends V> m),可理解为树枝的特有方法(Node没有),很明显这是安全式组合模式。

4.装饰器模式(Decorator)

定义:动态地给一个对象添加一些额外的职责。就扩展功能而言, 它比生成子类方式更为灵活。

UML类图:

应用:待补充

5.外观模式(Facade)

定义:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

UML类图:

应用:待补充

6.享元模式(Flyweight)

定义:运用共享技术有效地支持大量细粒度的对象。

UML类图:

应用:待补充

7.代理模式(Proxy)

定义:为其他对象提供一个代理以控制对这个对象的访问。

UML类图:

应用:待补充

3.3 行为型模式

1.责任链模式(Chain of Responsibility)

定义:解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。

UML类图:

应用:待补充

2.命令模式(Command)

定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。

UML类图:

应用:待补充

3.解释器模式(Interpreter)

定义:给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。

UML类图:

应用:待补充

4.迭代器模式(Iterator)

定义:提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。

UML类图:

应用:待补充

5.中介者模式(Mediator)

定义:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

UML类图:

应用:待补充

6.备忘录模式(Memento)

定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。

UML类图:

应用:待补充

7.观察者模式(Observer)

定义:定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。

UML类图:

应用:观察者模式

8.状态模式(State)

定义:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。

UML类图:

应用:待补充

9.策略模式(Strategy)

定义:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。

UML类图:

应用:待补充

10.模板方法模式(Template Method)

定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

UML类图:

应用:待补充

11.访问者模式(Visitor)

定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

UML类图:

应用:待补充

===参考===================

设计模式总结

设计模式与23种设计模式的简单介绍

浅谈UML中常用的9种图

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

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

相关文章

软件的演练场景编排的主要作用是什么?

在软件开发过程中&#xff0c;演练场景编排是一种重要的方法&#xff0c;旨在提供一个模拟真实环境的平台&#xff0c;帮助开发团队和用户测试和验证软件的功能、性能和适应性&#xff0c;那软件的演练场景编排的主要作用是什么&#xff1f; 软件演练场景编排是指通过创建特定的…

【Vue2.0源码学习】实例方法篇-数据相关方法

文章目录 0. 前言1. vm.$watch1.1 用法回顾1.2 内部原理 2. vm.$set2.1 用法回顾2.2 内部原理 3. vm.$delete3.1 用法回顾3.2 内部原理 0. 前言 与数据相关的实例方法有 3 个&#xff0c;分别是vm.$set、vm.$delete和vm.$watch。它们是在stateMixin函数中挂载到Vue原型上的&am…

MMDeploy SDK使用记录(ncnn)

参考&#xff1a;mmpose/projects/rtmpose at main open-mmlab/mmpose GitHub MMDeploy 提供了一系列工具&#xff0c;帮助我们更轻松的将 OpenMMLab 下的算法部署到各种设备与平台上。目前&#xff0c;MMDeploy 可以把 PyTorch 模型转换为 ONNX、TorchScript 等和设备无关的…

RabbitMQ 能保证消息可靠性吗

系列文章目录 消息队列选型——为什么选择RabbitMQ RabbitMQ 五种消息模型 RabbitMQ 能保证消息可靠性吗 系列文章目录前言一、消息可靠性的定义二、几种不可靠的场景三、防意外丢失1. 消息持久化2. 队列持久化3. 发布确认3.1 简单发布确认3.2 批量发布确认3.3 异步发布确认 4…

Vector - CAPL - CAPL入门 - 01

前面已经介绍了很多CAPL相关的函数极其应用&#xff0c;今天CAPL能够完成的功能来介绍在车载网络测试中都能够帮助测试工程师完成哪些工作&#xff1f;让我们对它有一个最基础的认识。 CAPL在总线中的应用 > 分析特定消息或特定数据 > 分析数据流量 > 创建和修改工具…

智慧班牌系统源码,相关技术:springboot,elmentui ,Quartz,jpa,jwt

电子班牌系统的主要功能包括&#xff1a;班级管理、学生信息管理、教师管理、课程管理、作业管理、考试管理、公告管理、评价管理、学校消息发布等。在班级管理方面&#xff0c;该系统可以实现教师对班级的整体管理以及学生个人信息的管理&#xff0c;包括个人信息、考试成绩、…

【Java】Java核心 72:XML (上)

文章目录 1 XML概述什么是XMLXML作用 2 编写第1个XML文件需求效果步骤 3 XML的组成&#xff1a;声明和元素XML组成文档声明元素&#xff08;标签、标记&#xff09; 4 XML的组成&#xff1a;属性、注释和转义字符属性的语法注释转义字符[实体字符]小结 1 XML概述 什么是XML 英…

rabbitmq设置允许外部访问

rabbitmq默认端口为15672,用户名和密码都为guest,是不允许外部访问的. 允许外部访问设置需要操作两步: 第一步:添加其它用户,guest只能用于本机 第二步:Virtual Host允许添加的用户访问,点击下图红色部分. spring配置 spring:rabbitmq:host: 192.168.101.57port: 5672username…

idea中有个目录不显示,磁盘中是有的

java项目src下有个目录data不显示 通过打开D盘看目录是有的&#xff0c;运行项目的时候报错&#xff0c;找不到目录下的文件。 解决方案&#xff1a; idea -> file -> seetings -> EDitor -> file types 打开页面后右侧显示有ignore files and folders 查看这里面有…

【Visual Studio】关于rc文件预处理器宏

问题 VS工程调试遇到一个问题&#xff1a;明明在 项目\属性&#xff0c;C/C\预处理器 页面定义了宏&#xff0c;为什么rc编译时没有影响&#xff1f; 百度后发现&#xff0c;和下方链接中问题很相似。 https://bbs.csdn.net/topics/50485796https://bbs.csdn.net/topics/50…

【运维】查询数据库每张表的数据及索引占用大小

【SQL】查询数据库每张表的数据及索引占用大小 SELECTa.*,CONCAT( a.总大小 / 1024000000, G ) 总大小G FROM(SELECTTABLE_SCHEMA,TABLE_NAME,sum( DATA_LENGTH ) 数据大小,sum( INDEX_LENGTH ) 索引大小,( sum( DATA_LENGTH ) sum( INDEX_LENGTH ) ) 总大小FROMinformation_s…

C# [unity]求顶点数量不等的两条曲线的中线

好久没写了.最近在尝试重写lgsvl导入地图数据的方式,地图同学提供的opendrive车道线计算不准,所以直接让他们导出经纬度的高精地图json数据,但是这种数据只有车道边界线,没有车道中心线, 基于只是想小改而非大改的前提下,还是要算出车道中心线.搞个小demo传上来,代码写的很拙劣…

宝塔定时任务实现磁盘使用率超阀值后自动发送邮件

服务器磁盘使用空间不足会产生各种不可预知的灾难&#xff0c;服务器上的应用几乎全部不能用&#xff0c;如果没有遇到过磁盘占满的问题&#xff0c;可能很难发现它。 步骤 安装邮件发送工具sendEmail磁盘检测并发送邮件shell脚本宝塔配置计划任务 安装邮件发送工具sendEmail …

【ROS】TF2坐标转换及实战示例

Halo&#xff0c;这里是Ppeua。平时主要更新C&#xff0c;数据结构算法…感兴趣就关注我吧&#xff01;你定不会失望。 文章目录 0.ROS中的坐标转换消息包0.1 geometry_msgs/TransformStamped0.2 geometry_msgs/PointStamped1.静态坐标转换1.1导入所需功能包1.2发布方实现1.3 …

多元分类预测 | Matlab粒子群算法(PSO)优化极限学习机(ELM)的分类预测,多特征输入模型。PSO-ELM分类预测模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元分类预测 | Matlab粒子群算法(PSO)优化极限学习机(ELM)的分类预测,多特征输入模型。PSO-ELM分类预测模型 多特征输入单输出的二分类及多分类模型。程序内注释详细,直接替换数据就可以用。程序语言为matlab,…

DALL-E2原理解读——大模型论文阅读笔记五

论文&#xff1a;https://cdn.openai.com/papers/dall-e-2.pdf 项目&#xff1a;https://openai.com/dall-e-2 一. 主要思想 利用CLIP提取的文本特征&#xff0c;级联式的生成图片。第一阶段通过prior将文本特征与图像特征进行对齐&#xff0c;第二阶段用扩散模型将视觉特征转…

简单demo演示Tomcat中Servlet

挺好玩的,有利于初学对容器和servlet接口规范的理解 具体代码 package org.apache;import javax.servlet.Servlet; import java.io.FileReader; import java.io.IOException; import java.util.Properties; import java.util.ResourceBundle; import java.util.Scanner;/*** a…

一文了解HTTP协议

文章目录 前言概念协议传输超文本 HTTP 协议的格式HTTP 请求HTTP 响应 总结 前言 在这之前&#xff0c;可以看看我之前的文章&#xff0c;也是关于协议的。 TCP/IP 协议详解 UDP协议详解 我们在打开一个网页的时候通常都会注意到网址的前面有一个统一的标识http://&#xf…

智慧校园电子班牌系统源码

电子班牌系统的主要功能包括&#xff1a;班级管理、学生信息管理、教师管理、课程管理、作业管理、考试管理、公告管理、评价管理、学校消息发布等。在班级管理方面&#xff0c;该系统可以实现教师对班级的整体管理以及学生个人信息的管理&#xff0c;包括个人信息、考试成绩、…

Long型参数传到前端精度丢失,后两位变为00,导致传值错误,解决方案

问题&#xff1a; 后端id字段为Long型&#xff0c;起初采用自增主键&#xff0c;没有问题&#xff1b;由于业务需要改为雪花id&#xff0c;后端可正常运行&#xff0c;传递到前端精度丢失&#xff0c;后两位变为00。 解决方案&#xff1a; 后端将属性转为字符串传递&#xff0…