设计模式总结
设计模式的六大原则
开放-封闭原则(OCP) (总原则)
Open-Close Principle:该对扩展开放,对修改关闭。
目的就是保证程序的扩展性好,易于维护和升级。
开放-封闭原则是面向对象设计的核心所在, 开闭原则是Java世界里最基础的设计原则。
开闭原则被称为面向对象设计的基石,实际上,其他原则都可以看作是实现开闭原则的工具和手段。通俗来说就是,开发一个软件时,应该对其进行功能扩展,而在进行这些扩展时,不需要对原来的程序进行修改。
单一职责原则(SRP)
Single-Responsibilitiy Principle:对一个类而言,应该仅有一个引起它变化的原因。
优点:
1.降低类的复杂度
2.提高类的可读性,提高系统的可维护性。
3.降低变更引起的风险。
单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。单一职责适用于接口,类,同时也适用于方法。
在类中新加一个方法的修改方式,虽然也违背了SRP,但在方法级别上却是符合SRP的,因为它并没有动原来方法的代码。在开发中,需要根据实际情况来确定。但对于接口一定要做到单一职责,对于类的设计尽量做到只有一个原因引起变化。
里氏替换原则(LSP)
Liskov Substitution Principle:一个软件实体如果适用一个父类的话,那一定是适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换其父类对象,而不改变程序逻辑。
要满足上面的要求那就需要
- 子类可以扩展父类的功能,但是不能改变父类原有的功能。
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。(但在实际代码开发过程中,可能需要在某些特殊情景下重写父类的某个方法,不建议,但是为了代码的统一这么写个人也是觉得可以接受的)
依赖倒置原则(DIP)
Dependence Inversion Principle:是一个类与类之间的调用规则。这里的依赖就是代码中的耦合。高层模块不应该依赖底层模块,二者都应该依赖其抽象;抽象不依赖细节;细节应该依赖抽象、接口编程。
问题由来:
类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
依赖倒置原则的核心思想是面向接口编程。
在实际编程中,我们一般需要做到如下2点:
- 低层模块尽量都要有抽象类或接口,或者两者都有。
- 变量的声明类型尽量是抽象类或接口。
接口隔离原则(ISP)
Interface Segregation Principle:用于恰当的划分角色和接口,具有两种含义:1、用户不应该依赖它不需要的接口;2、类间的依赖关系应该建立在最小的的接口上。
单一职责原则,要求行为分离,接口细化,感觉有些相同。但实际上,单一职责原则要求类与接口的职责单一,注重的是职责,没有要求接口尽量的少。
在接口隔离原则中,要求尽量使用多个专门的接口。专门的接口也就是提供给多个模块的接口。提供给几个模块就应该有几个接口,而不是建立一个臃肿庞大的接口,所有的模块都可以访问。
但是接口的设计是有限度的。接口的设计粒度越小系统越灵活,但是接口太多也就使得结构复杂,维护难度大。因此实际中,怎样把握就靠开发的经验和常识了。
迪米特原则(LoD)
Law of Demeter(最小知识原则):一个对象应该对其他对象有最少的了解。通俗来说就是,一个类对自己需要耦合或者调用的类知道的尽可能的少。
迪米特原则核心观念就是:类间解耦,弱耦合。
从迪米特法则的定义和特点可知,它强调以下两点:
从依赖者的角度来说,只依赖应该依赖的对象。
从被依赖者的角度说,只暴露应该暴露的方法。
迪米特法则要求限制软件实体之间通信的宽度和深度,正确使用迪米特法则将有以下两个优点:
- 降低了类之间的耦合度,提高了模块的相对独立性。
- 由于亲合度降低,从而提高了类的可复用率和系统的扩展性。
合成复用原则(CARP)
Composite/Aggregate Reuse Principle :尽量使用组合实现代码复用,而不使用继承。
继承复用子类和父类的耦合度很高,如果修改了父类,就需要修改所有的子类。
不过个人认为在业务开发过程中使用模板方法的时候就需要通过继承来复用,有时候也会引入一些不必要的接口参数,这个就看自己的衡量了
设计模式总结
设计模式要⼲的事情就是解耦。
可分为三大类:
- 创建型模式是将创建和使⽤代码解耦
- 结构型模式是将不同功能代码解耦
- ⾏为型模式是将不同的⾏为代码解耦
创建型模式
共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
结构型模式
共七种:适配器模式、装饰器模式、代理模式、桥接模式、组合模式、享元模式、门面模式。
行为型模式
共十一种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、状态模式、访问者模式、中介者模式、解释器模式、命令模式、备忘录模式。
还有一种不在23种设计模式种的委派模式
设计模式使用频率
| 类型 | 高频 | 低频 |
|---|---|---|
| 创建型模式 | 单例模式,工厂方法模式,建造者模式 | 原型模式、抽象工厂模式 |
| 结构型模式 | 适配器模式、装饰器模式、代理模式、门面模式 | 桥接模式、组合模式、享元模式 |
| 行为型模式 | 策略模式、模板方法模式、观察者模式、责任链模式 | 迭代器模式(一般作为基础类库提供)、访问者模式、中介者模式、状态模式、解释器模式、命令模式、备忘录模式 |
不同设计模式比较
每个设计模式都应该由两部分组成:第⼀部分是应⽤场景,即这个模式可以解决哪类
问题;第⼆部分是解决⽅案,即这个模式的设计思路和具体的代码实现。
如果我们只从设计模式的设计思路来看,就会觉得很多设计模式看起来都很类似。但是,设计模式之间的主要区别还是在于设计意图,也就是应用场景。
单纯地看设计思路或者代码实现,有些模式确实很相似,⽐如策略模式和⼯⼚模式。
策略模式从代码结构上来,它⾮常像⼯⼚模式,都包含三部分: 策略(工厂对象)的定义、创建和使⽤。
它们的区别在于,策略模式侧重算法的应⽤场景,⽤来解决根据运⾏时状态从⼀组策略中选择合适的策略的问题,⽽⼯⼚模式侧重封装对象的创建过程,这⾥的对象没有任何业务场景的限定,可以是策略,但也可以是其他东⻄。从设计意图上来,这两个模式完全是两回事⼉。
命令模式VS策略模式
在策略模式中,不同的策略具有相同的⽬的、不同的实现、互相之间可以替换。⽐如,BubbleSort、SelectionSort 都是为了实现排序的,只不过⼀个是⽤冒泡排序算法来实现的,另⼀个是⽤选择排序算法来实现的。
⽽在命令模式中,不同的命令具有不同的⽬的,对应不同的处理逻辑,并且互相之间不可替换。
参考文献:
设计模式六大原则
实际开发过程中,并不一定是要求所有代码都遵循上述设计原则,要考虑人力,时间,质量成本,要在适当的使用场景遵循设计原则,不能为了设计而设计。所有的设计模式和设计原则最终都是为了服务于业务。
相关文章:
设计模式总结
设计模式的六大原则 开放-封闭原则(OCP) (总原则) Open-Close Principle:该对扩展开放,对修改关闭。 目的就是保证程序的扩展性好,易于维护和升级。 开放-封闭原则是面向对象设计的核心所在, 开闭原则是Java世界里最基础的设计原则。 开闭…...
【K8S系列】深入解析Pod对象(一)
目录 序言 1.问题引入 1.1 问题描述 2 问题解答 2.1 pod 属性 2.1.1 NodeSelector 2.1.2 HostAliases 2.1.3 shareProcessNamespace 2.1.4 NodeName 2.1.5 其他pod属性 2.2 容器属性 2.2.1 ImagePullPolicy 2.2.2 Lifecycle 3 总结 4. 投票 序言 任何一件事情&am…...
JVM学习.02 内存分配和回收策略
1、前言《JVM学习.01 内存模型》篇讲述了JVM的内存布局,其中每个区域是作用,以及创建实例对象的时候内存区域的工作流程。上文还讲到了关于对象存货后,会被回收清理的过程。今天这里就着重讲一下对象实例是如何被清理回收的,以及清…...
logstash+elasticsearch+Kibana(ELK)日志收集
文章目录一.安装ELK 7.17二.为Elasticsearch设置密码三.配置logstash四.springboot整合logstash五.spring整合Elastic Search一.安装ELK 7.17 不要一股脑执行以下语句,请观察修改要修改的地方 安装logstash # logstash安装docker run -d --name logstash \-p 5043:5043 -p 5…...
今天面试了一个2年Java经验的
今天去面试了一个26岁的程序员,看了简历,2年经验,本科,写得很牛叉。 Spring cloud alibaba全家桶、redis,分布式锁,服务调用,数据库事务,线程,Zookeeper、Dubbo 、Rabbi…...
逻辑覆盖测试用例设计
逻辑覆盖测试用例设计 实验目标 能够依据程序画出程序流程图理解常用覆盖方法的内涵理解常用覆盖方法的强弱关系能够使用常用覆盖方法设计测试用例 背景知识 白盒测试通常采用静态测试方法和动态测试方法开展。动态测试是参照系统需求或测试规则,通过预先设计一…...
面试官:说一下MySQL中的锁机制吧
5. 1MySQL有哪些锁? 为保证数据的一致性,需要对并发操作进行控制,因此产生了锁。同时锁机制也为实现MySQL的各个隔离级别提供了保证。 锁冲突 也是影响数据库并发访问性能的一个重要因素。所以锁对数据库而言显得尤其重要,也更加…...
STL库中list的迭代器实现痛点分析
前文本篇文章准备换个模式,之前都是先详解模拟实现,但是模拟实现的基本逻辑大多数老铁都是明白的,所以我们这次主要讲解STL库中list的独特性,也就是模拟实现中的重难点文末有模拟实现的源码一,list实现的特殊类list实现…...
字符编码对比(GBK、Unicode、UTF-8)
摘要我们在网上能看到各种文字和符号,那么它们是怎么存储和转化的,还有我们常常提及的UTF-8,为什么都要设置这种编码方式,这里就探讨下。字符集字符集:就是各国文字、符号、数字的集合。常见的字符集有:ASC…...
【百面成神】Redis基础11问,你能坚持到第几问
前 言 🍉 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:纯手打总结面试题,自用备用 🌰 文章简介:Redis最基础、重要的11道面试题 文章目录…...
十大排序算法极简汇总篇
说明 十大排序算法可以说是每个程序员都必须得掌握的了,如果你们像从 0 详细学习每一篇,那么你们可以看前面的文章。 但是呢,有些人可能已经学过,想要快速复习一下,看看代码怎么写的,那么可以看这篇十大排…...
数据结构笔记
文章目录第一章:数据结构与算法第二章:稀疏数组和队列一 、稀疏sparsearray 数组(一)案例需求(二)稀疏数组介绍(三)应用实列(四)代码实现二、队列(…...
web前端框架——Vue的特性
目录 前言: 一.vue 二.特性 1.轻量级 2.数据绑定 3.指令 4.插件 三.比较Angular 、React 、Vue 框架之间的比较 1. Angular Angular的优点: 2. React React 的优点: 3.vue 3.Vue的优点: 前言: 本篇文章…...
提权工具推荐(PEASS-ng、linpeas_linux_amd64、winPEASany_ofs)
介绍 在这里,您可以找到适用于Windows、Linux/Unix*和MacOS的权限提升工具。 这些工具搜索您可以利用的可能的本地权限提升路径,并用漂亮的颜色打印给您,这样您就可以很容易地识别错误配置。 查看book.hacktricks.xyz中的本地Windows权限提升检查表WinPEAS-Windows本地权限…...
Spark - 继承 FileOutputFormat 实现向 HDFS 地址追加文件
目录 一.引言 二.源码浅析 1.RDD.saveAsTextFile 2.TextOutputFormat 3.FileOutputFormat 三.源码修改 1.修改文件生成逻辑 - getRecordWriter 2.允许目录存在 - checkoutputSpecs 3.全部代码 - TextOutputFormatV2 四.追加存储代码实战 五.总结 一.引言 Output d…...
树莓派编程控制继电器及继电器组
目录 一,继电器说明 ● 继电器接口说明 ① 继电器输入端: ② 继电器输出端: 二,树莓派控制继电器 三,树莓派控制继电器组 一,继电器说明 通俗点讲,可以把继电器理解成是一些功能设备的控制开关。 ● LOW&#…...
oracle和mysql的区别
Oracle与MySQL的区别以及优缺点 MySQL的特点 1、性能卓越,服务稳定,很少出现异常宕机; 2、开放源代码无版本制约,自主性及使用成本低; 3、历史悠久,社区和用户非常活跃,遇到问题及时寻求帮助…...
<Linux开发> linux应用开发-之-uart通信开发例程
一、简介 串口全称叫做串行接口,串行接口指的是数据一个一个的按顺序传输,通信线路简单。使用两条线即可. 实现双向通信,一条用于发送,一条用于接收。串口通信距离远,但是速度相对会低,串口是一种很常用的工…...
基于深度学习的安全帽检测系统(YOLOv5清新界面版,Python代码)
摘要:安全帽检测系统用于自动化监测安全帽佩戴情况,在需要佩戴安全帽的场合自动安全提醒,实现图片、视频和摄像头等多种形式监测。在介绍算法原理的同时,给出Python的实现代码、训练数据集,以及PyQt的UI界面。安全帽检…...
Linux - 进程控制(进程替换)
0.引入创建子进程的目的是什么?就是为了让子进程帮我执行特定的任务让子进程执行父进程的一部分代码如果子进程想执行一个全新的程序代码呢? 那么就要使用进程的程序替换为什么要有程序替换?也就是说子进程想执行一个全新的程序代码ÿ…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
