编程中的智慧四:设计模式总览

前面三篇我们通过从一些零散的例子,和简单应用来模糊的感受了下设计模式在编程中的智慧,从现在开始正式进入设计模式介绍,本篇将从设计模式的7大原则、设计模式的三大类型、与23种设计模式的进行总结,和描述具体意义。

设计模式体系结构图

七大原则

开闭原则(OCP,Open Close Principle )

官方解释:对扩展开放软件实体应当对修改关闭(Software entities should be open for extension,but closed for modification)


白话解读:合成复用原则、里氏替换原则相辅相成,都是开闭原则的具体实现规范
就是有新的业务的时候,尽可能扩展展新类而不是修改旧类,实际开发的时候大家基本上都会这么做,这样对之前的业务影响比较小,所以很多原则设计模式就贯穿在日常开发中。
 

里氏替换原则(LSP,Liskov Substitution Principle)

👀官方解释:继承必须确保超类所拥有的性质在子类中仍然成立(Inheritance should ensure that anyproperty proved about supertypeobjects also holds for subtype objects)

是不是完全看不明白,俺也一样。

大白话:其实就是当我们需要开发功能的时候尽量通过继承父类,扩展父类功能的;而不是直接在原本的父类上修改。

依赖倒置原则(DIP,Dependence Inversion Principle)

官方定义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该以来抽象(High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions )

大白话:面向接口编程,而不是面向类编程:

例如:Controller里注入的是service接口而不是ServiceImpl,这样Controller就不用关心servcieImpl到底依赖的那些dao,同理可以推广的ServiceImpl依赖的是dao接口而不用关心具体实现。

单一原则(SRP,Single Responsibility Principle)

官方定义:一个类应该有且仅有一个引起他变化的原因,否则这个类应该被拆分(There should never be more than one reason for a class to change)

大白话:每个类只负责自己领域类的事情,而不是一篮子事情:当然要注意不是一个类只有一个方法。

例如:FileService可以处理文件上传下载方法,但是注册登陆等方法就不该放入该类中

接口隔离原则(ISP,Interface Segregation Principle)

官方定义:一个类对另一个类的依赖应该建立在最小的接口上(The dependency of one class to another on should depend on the smallest possible interface)

大白话:类应该建立自己专用的接口,而不是建立一个万能接口。

其实这个可以配合上面两个看,如果建立的万能接口,同时又要满足上面依赖倒置原则,那必定实现不了单一原则。

合成复用原则(CRP,Composite Reuse Principle)

由叫组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)

软件复用时,要尽量先使用组合或者聚合等关联关系实现,其次才考虑使用继承关系实现。

大白话:优先是用组合而不是继承,这个是通用原则了,主要还是继承扩展起来没那么方便。

迪米特法则(LOD,Law of Demeter)

低耦合,高内聚。

最少知识原则(Least Knowledge Principle,.LKP)
只与你的直接朋友交谈,不跟“陌生人”说话 (TaIk only to your immediate friends and not to strangers)


其实就是引入一个中间者来进行交互Controller层不直接和Dao层直接交互

设计模式与组件生命周期关系图

以Java为例,通常我们会以结构型设计模式去构建类的类信息,通过创建型设计模式去创建对象,通过行为模式去控制对象的行为。

23种设计模式概述

前面三篇文章,基本上都多少涉及到了一点,这里咱们做个简单归纳的归纳总结,后面咱们咱们会一个一个的拆分。

结构型设计模式

外观模式(Facade)

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

例子:在一个电商系统中,处理订单可能涉及多个子系统,如支付系统、库存系统、物流系统等。外观模式可以提供一个统一的接口来处理订单,从而简化客户端的调用。

适配器模式(Adapter)

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

例子:MyBatis中的ResultSetHandler将JDBC的结果集转换为自定义的对象类型。这个过程就是适配器模式的应用,将不兼容的接口进行适配。

桥接模式(Bridge)

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

例子:Spring的JdbcTemplate和各种具体的数据库实现之间的分离。JdbcTemplate提供抽象操作,而具体的数据库操作由不同的DataSource实现,二者可以独立变化。

组合模式(Composite)

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

例子:在一个文件系统中,文件和文件夹都可以视为节点。文件夹可以包含文件和其他文件夹,这形成了一个树形结构。组合模式使得文件和文件夹的操作一致。这个例子可能有过文件处理系统的小伙伴可能才好理解,再举一个列子:一个管理系统他的菜单树结构的,子与父结构相同这样是不是就好理解了一级菜单二级菜单嘛,无限套娃就行。

装饰模式(Decorator)

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

例子:在一个图形编辑器中,可以对图形对象添加不同的装饰(如边框、阴影)。装饰模式可以动态地添加这些装饰,而不需要改变图形对象的类。

享元模式 (Flyweight)

运用共享技术有效地支持大量细粒度的对象。 例子:在一个文字处理系统中,每个字符都是一个对象。如果每个字符都单独存储,会占用大量内存。享元模式通过共享相同的字符对象,减少内存的使用。

代理模式(Proxy)

其他对象提供一种代理以控制对这个对象的访问。

例子:在一个远程服务调用系统中,客户端通过代理对象来访问远程服务。代理对象处理与远程服务的通信和数据传输,客户端只需调用代理对象的接口。SpringCloud种的Open Feign就是这个思想呢,当然代理我们一般分为静态代理和动态代理,但是现在很多时候静态代理和装饰器思想很接近,所以很多时候代理模式指的是动态代理,而java实现动态代理由离不开jdk或cglib,详细讨论的时候这一块将是重点。同样提到这里咱们就不得再提一下Spring种的Aop咯。

Spring的AOP也是代理模式的一个典型应用。通过创建代理对象,Spring AOP可以在方法调用前后添加额外的逻辑,如事务管理、权限检查等。

MyBatis也使用代理模式生成Mapper接口的实现类,调用实际的SQL操作。这个在框架中使用特别多,后面一定要好好说说。

创建型设计模式

创建模式主要的关注点是怎样将对象创建出来,将对象创建与使用进行剥离。像Spring框架就是依赖创建型设计模式,将我们开发者从对象的创建给剥离出来,对象的创建全部交给Spring托管,咱们安心写自己业务代码(方法的调用即可)。

单例模式(Singleton Pattern)

单例模式,在系统里,你要判断一下,如果有一些类,只需要一个实例对象就可以了,那就给那个类做成单例的模式(关键点就是构造方法私有化)Spring中的Bean对象默认都是单例的,后面在介绍具体的设计模式的时候在详细看代码。

简单工厂模式

工厂模式的核心思想,其实就是不要自己在代码里手动new一个实现类对象出来,因为那样的话,调用方就不是面向接口编程了,你还得自己去实现了。所以一般都是用工厂的思想来提供所有实现类实例,然后调用方面向接口来编程即可,接口不变,调用方代码不用变。

现在基本上很少去自己实现工厂模式了,因为有Spring框架,Spring的容器其实本质上就是个大工厂的概念,将你需要的对象都放到Spring容器里,需要的时候问Spirng取就完事。

工厂方法模式(Factory Method)

模板方法模式+简单工厂模式,简单工厂模式

抽象工厂模式(Abstract Factory)

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。在一个工厂中聚合多个同类产品的创建方法。简单理解为“工厂的工厂即可”。

建造者模式(Builder)

构造一个复杂的对象,很多的属性,有些属性构造的时候需要做一些校验,格式转换;

举个例子:当我们销售系统收到一笔订单的时候,在构建订单的时候需要对订单金额基础的校验、对产品的代码、产品类型做一些转换、供应商等。

原型模式(Prototype)

原型模式,以某一个对象为原型,然后对这个对象进行拷贝,得到拷贝后的另外一个对象

例子:很多BeanUtils之类的都有类似的功能,后面我们在分析具体的原理和对比他们的性能等。

行为型设计模式

责任链模式(Chain Of Responsibility)

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有对象处理它为止。

在Spring框架中,过滤器链的实现就体现了责任链模式的应用。每个过滤器负责处理请求的一部分逻辑,然后将请求传递给链中的下一个过滤器。这样就形成了一条过滤器链,所有的过滤器按顺序依次执行。

策略模式(Strategy)

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

例子:在一个支付系统中,支持多种支付方式(如支付宝、微信、信用卡、PayPal、比特币等)。每种支付方式是一个策略,用户可以在支付时选择不同的支付方式。

模版方法(Template Method)

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

例子:在一个文档处理系统中,可以有不同类型的文档(如Word文档、PDF文档等)的导出。导出的步骤大致相同:打开文档、读取内容、写入目标格式、关闭文档。具体的读取和写入步骤可以由子类实现。

命令模式(Command)

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

例子:在一个智能家居系统中,可以有各种命令(如小爱同学打开灯、关闭灯、调节温度等)。每个命令可以封装为一个对象,用户可以对命令进行操作,如执行、撤销等。

其实对于前后端分离项目,用户前端每次执行一个操作,对应后端的每个请求都可以看作是一个命令的执行,我们提供给前端的接口其实就是一个个封装的对象。

观察者模式(Observer)

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

例子:在一个股票交易系统中,投资者可以订阅股票价格的变化。当股票价格发生变化时,系统会通知所有订阅了该股票的投资者。

这个在Spring中的监听机制,其实就是可以看作是一个观察者模式,当模式泛化以后可以将消息中间件中的主题中的一组生产者一组消费者看作观察者模式。

访问者(Visitor)

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

例子:在一个编译器中,可以有不同的操作(如语法检查、代码优化、代码生成等)作用于语法树的各个节点。每个操作可以通过访问者模式实现。

状态模式(State)

允许对象在内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

例子:在一个订单处理系统中,订单可以有不同的状态(如新建、已支付、已发货、已完成等)。每种状态下订单的行为可能不同,比如在已支付状态下可以发货,但在新建状态下不可以。

这个状态模式和策略模式很想,不同的是状态模式有一个自动流转的状态机通过状态的不同来实现不同的算法。

解释器模式(Interpreter)

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

例子:在一个数学表达式计算器中,可以定义表达式的文法,并使用解释器模式来解析和计算表达式的值。

这玩意不知道咋解释,实际项目种使用的比较少,之前在科技部门做个一个通用的消息触达平台,定义了一些简单的占位符,通过占位符规则替换一些数据,应该类似解释器。

泛化到语言层面如Java 语言的Javac命令可以将Java源代码解析成Class文件,抑或现在比较火的Transformer框架中的编码器与解码器,将各种结构化数据解析成一组组向量后在来处理相似性问题,这个似乎更满足解释器模式的概念。这个模式先放一放,如果有小伙伴有比较深入的研究欢迎私信一起交流。

迭代器模式(Iteration)

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

例子:在一个集合框架中,可以有各种集合(如数组、列表、集合等)。迭代器模式提供了一个统一的接口来遍历这些集合中的元素。

这种Java已经有很成熟的API了,咱们就不用自己去实现了,设计模式一定不能为了设计而设计,一定是为了解决实际问题。

中介者模式(Mediator)

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

例子:在一个聊天系统中,用户之间的消息传递通过一个中介者对象(如聊天服务器)进行,用户不需要直接知道其他用户的存在。

备忘录模式(Memento)

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后恢复对象到先前的状态。

例子:在一个文本编辑器中,可以有撤销和恢复功能。编辑器可以在执行某个操作前保存当前状态,以便用户需要时可以恢复到该状态。

其实Java中的序列化与反序列化可以看作是这个思想的扩展,需要保留的时候序列化的文件中,

设计模式带来的一些思考:

1、为什么学习设计模式

其实回答这个问题的时候,很多培训机构的老师或者网上资料都说设计模式是源码的基础,只有学会了设计模式才能看懂源码之类的观点。

这里的观点可能不太一样,设计模式也好抑或其他框架也罢,都是为了我们解决实际问题而设计出来的,有了设计模式的思想很多时候会给我们软件设计带来一些启发,这种场景是否可以有xxx模式的思想来解决呢?

其次任何一个成熟的项目都不可能由一个人来完成,设计模式思想的运用可以在团队合作的时候来规范团队。举个例子:在参与基金销售系统开发的时候,他的交易可以各种业务如:基金的认购、申购、赎回、修改分红方式等,每一种业务都有对应的处理逻辑,但是他们都需要和基金管理公司交互而和基金公司交互都是通过文件的形式。这样他们共同点可以抽象出来,那就是文件的处理可以放到模板方法统一实现,文件解析后的数据,再有个各子域去实现。这样子域可以由不同的人员来开发,代码风格更加统一好维护。

总结

在软件开发中,设计模式不仅仅是技术上的工具,更是一种思维方式和解决问题的哲学。它们通过丰富的实践和理论积累,帮助开发者在面对复杂需求和变化时保持清晰的思路和高效的开发策略。无论是单例模式的实例唯一性,还是策略模式的算法灵活性,设计模式都在实际项目中展现出其独特的价值。通过不断学习和应用设计模式,我们能够更好地理解和运用面向对象设计的原则和技巧,从而打造出更加健壮和可维护的软件系统。设计模式的智慧不仅体现在代码中,更融入到整个软件开发的文化与实践中,成为提升团队能力和项目质量的重要支柱,同样切记不能为了设计而设计,目前各种语言与框架已经很成熟,使用这些设计模式的时候一定要采取审慎原则。拿不定主意的时候多和公司资深前辈沟通。

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

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

相关文章

新形势下职业教育人工智能人才培养策略

一、引言 随着人工智能技术的飞速发展,社会对人工智能人才的需求日益增长。职业教育作为培养实用型人才的重要基地,应积极响应市场需求,加强人工智能人才的培养。然而,当前职业教育在人工智能人才培养方面仍存在一些问题&#xf…

C++树形结构(总)

目录 一.基础: 1.概念: 2.定义: Ⅰ.树的相关基础术语: Ⅱ.树的层次: 3.树的性质: 二.存储思路: 1.结构体存储: 2.数组存储: 三.树的遍历模板: 四.…

App用户从哪来?Xinstall全渠道数据统计告诉你答案!

在移动互联网时代,App已经成为了我们日常生活中不可或缺的一部分。然而,对于App运营者来说,如何了解用户的来源,从而优化推广策略,一直是一个难题。今天,我们就来科普一下App用户来源分析的重要性&#xff…

使用idea创建Javaweb项目(步骤)

第一步创建Javaweb项目 File>New>Project 第二步 勾选Web Application >Next 然后就是进行起名,完成。 完成创建项目,检查是否文件齐全 配置tomcat 配置好,就能启动tomcat,显示首页 导入jar包。导入进项目&#xf…

博客建站4 - ssh远程连接服务器

1. 什么是SSH?2. 下载shh客户端3. 配置ssh密钥4. 连接服务器5. 常见问题 5.1. IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! 1. 什么是SSH? SSH(Secure Shell)是一种加密的网络协议,用于在不安全的网络中安全地远程登录到其他…

LC617-合并二叉树

文章目录 1 题目描述2 思路优化代码完整输入输出 参考 1 题目描述 https://leetcode.cn/problems/merge-two-binary-trees/description/ 给你两棵二叉树: root1 和 root2 。 将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另…

解决 elementUI 组件在 WebStorm 中显示为未知标签的问题

解决 elementUI 组件在 WebStorm 中显示为未知标签的问题 一、问题 自从转到 ts 之后,编辑器就一直提示用到的 elementUI 标签未知,一直显示一溜黄色警示,很烦: 二、解决 把它改成大写就可以了。 如下: 把整个项目…

视频编码中算术编码原理详解

介绍 最近研究 CABAC 熵编码原理,因此在剖析 CABAC 熵编码原理之前,先复习下算术编码的原理。算术编码是图像压缩的主要算法之一。 是一种无损数据压缩方法,也是一种熵编码的方法。和其它熵编码方法不同的地方在于,其他的熵编码方…

2024视频改字祝福 豪车装X系统源码uniapp前端源码

源码介绍 uniapp视频改字祝福 豪车装X系统源码 全开源,只有uniapp前端,API接口需要寻找对应的。 创意无限!AI视频改字祝福,豪车装X系统源码开源,打造个性化祝福视频不再难! 想要为你的朋友或家人送上一份特别的祝福…

使用 Nginx 统计固定源 IP 访问项目的时间

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] &#x1f4f1…

相交链表-list

160. 相交链表 - 力扣(LeetCode) 链表没有直接求几个的size 用哈希表把heada存进哈希,在用哈希表的count(b),这个计算b出现几次,没出现就是0; class Solution { public:ListNode *g…

【计算机系统架构】从0开始构建一台现代计算机|二进制、布尔运算和ALU|第2章

博主简介:努力学习的22级计算机科学与技术本科生一枚🌸博主主页: Yaoyao2024往期回顾: 【计算机系统架构】从0开始构建一台现代计算机|布尔代数和基础逻辑门|第一章每日一言🌼: 勇敢的人,不是不落泪的人&am…

张量的基本使用

目录 1.张量的定义 2.张量的分类 3.张量的创建 3.1 根据已有数据创建张量 3.2 根据形状创建张量 3.3 创建指定类型的张量 1.张量的定义 张量(Tensor)是机器学习的基本构建模块,是以数字方式表示数据的形式。PyTorch就是将数据封装成张量…

昇思25天学习打卡营第10天|ResNet50图像分类

学习如何使用MindSpore框架和ResNet50网络进行图像分类。 图像分类是计算机视觉的基础任务,就是给定一张图片,判断它属于哪个类别,比如猫、狗、飞机等。 ResNet50是一种深度学习网络,由微软实验室的何恺明在2015年提出&#xff…

odoo17 win11布署

今天重装系统,正巧试了下odoo17的布置,系统配置: windows 11专业版,python 3.12.3 postgresql postgresql-13.15-1-windows-x64 安装过程中适当调了一下python库版本 # The officially supported versions of the following pa…

springboot+vue+mybatis校园二手交易平台+PPT+论文+讲解+售后

现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本校园二手交易平台就是在这样的大环境下诞生,其可以帮助使用者在短时间内处理完毕庞大的数据信息&#…

揭秘App使用统计:Xinstall如何助你洞悉用户行为

在移动互联网时代,App使用统计对于开发者而言至关重要。通过深入了解用户的使用习惯和行为模式,开发者可以优化产品设计、提升用户体验,并制定出更精准的营销策略。然而,如何进行全面的App使用统计并分析数据,一直是困…

尚庭公寓开发笔记(一)

本篇文章讲的是p前五十节课 可以关注后续 传统的数据库设计流程 分为三个阶段:概念模型设计阶段 逻辑模型设计阶段 物理模型设计 阶段 为本项目设计数据库模型 地图的存储只需要保存经纬度就ok 本项目采用的是mysql数据库 所有表都使用的是innnodb存储引擎 我们使…

昇思MindSpore学习入门-数据采样

为满足训练需求,解决诸如数据集过大或样本类别分布不均等问题,MindSpore提供了多种不同用途的采样器(Sampler),帮助用户对数据集进行不同形式的采样。用户只需在加载数据集时传入采样器对象,即可实现数据的…

美业SaaS门店收银系统怎么管理订单?博弈美业系统App实操|美业系统Java源码

- 打开博弈美业 - 首页点击订单管理 - 选择想查询的相应订单即可 美业门店管理系统Java源码、美业店务系统演示视频请私信