设计模式学习

文章目录

  • 前言
  • 设计模式的七大原则
    • 单一职责原则
    • 开放封闭原则
    • 里氏替换原则
    • 依赖倒转原则
    • 接口隔离原则
    • 合成复用原则
    • 迪米特原则
    • 总结
  • GoF二十三种设计模式
    • 创建型模式(五种)
    • 结构型模式(七种)
    • 行为型模式(十一种)
  • 游戏中的设计模式

前言

设计模式是程序员的内功,随着工作经验的增长,愈发认识到设计模式的重要性。本篇文章是对设计模式的总结,随着日后在开发和学习过程中接触和使用更多的设计模式再以实际的应用案例记录笔者的学习过程。

设计模式的七大原则

单一职责原则

就一个类而言,应该仅有一个引起它变化的原因。

在系统中,一个类大到模块,小到方法,承担的职责越多,被复用的可能性就越小。
而且这个类承担的职责过多,就可能造成一个职责的改变影响其他职责。
设计类时需要设计人员发现类的不同职责并将其分离,这通常需要设计思维和实践经验。

开放封闭原则

软件实体(类或模块)应该对扩展开放,对修改关闭。即类模块应该是可扩展的,但是不可修改。

开闭原则就是指在尽量不修改原有代码的情况下进行扩展。
为了实现开闭原则,我们需要对系统进行抽象化设计,抽象化是开闭原则的关键。
我们通过接口,抽象类来定义系统的抽象层,在通过具体类来实现扩展。如果需要修改系统的行为,无需对抽象层进行任何的改动,只需要增加具体类来实现新的业务,实现在不修改已有代码的基础上扩展系统功能,达到开闭原则的要求。
带来的好处:
让系统具有良好的灵活性、复用性和可扩展性;
稳定性高,不需要反反复复修改源代码,导致原工程出错;
不用反复修改测试类;
实现方式:接口,抽象类。

里氏替换原则

将一个基类对象替换成子类对象,程序不应产生任何错误或异常。

由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型对对象进行定义,而在运行时在确认其子类类型,用子类对象替换父类对象。
通常做法:将父类设计为抽象类或者接口,让子类继承父类或实现父类接口,并实现在父类中声明的方法。运行时,子类实例代替父类实例。
好处:通过子类可以代替父类的特性,可以很方便的扩展系统的功能,无需修改原有子类的代码,增加了新功能可以通过增加一个新的子类来实现。

依赖倒转原则

高层模块不应该依赖底层模块,它们都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。

通常做法:使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型转换等,而不要用具体类来做这些事情。
在实现依赖倒转原则时,需要针对抽象层进行编程,而将具体类的对象通过依赖注入的方式注入到其他对象中,
依赖注入是指当一个对象要与其他对象发生关系时,通过方法参数来注入所依赖的对象。
常用方法有3种
1)构造注入:构造注入是指通过构造函数来传入具体类的对象。
2)设值注入:是指通过Setter方法来传入具体类的对象。
3)接口注入:是指通过在接口中声明的业务方法来传入具体类的对象。
这些方法在定义时使用的是抽象类型,在运行时在传入具体类型的对象,由子类对象来覆盖父类对象。
原则: 一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,
好处: 在引入抽象层后,系统将具有很好的灵活性,在程序中应该尽量使用抽象层进行编程,而将具体类写在配置文件中,这样一来,如果系统发生变化,只需要对抽象层进行扩展,并修改配置文件,而无须修改原有系统的源代码,在不修改的情况下来扩展系统的功能,满足开闭原则的要求。

接口隔离原则

每个接口中不存在派生类用不到却必须实现的方法,如果不然,就要将接口拆分,使用多个隔离的接口。

实现:“定制服务”,将大接口的众多方法根据职责分别放在不同的小接口中,每个接口只包含一个子模块所需的方法即可,这种方法也成为了定制服务,即为不同模块提供宽窄不同的接口。

如果不遵循接口隔离原则,实现一个接口就需要实现该接口中定义的所有方法,就会带来具体类中出现大量空方法,无用代码。
造成实现类不知道用哪个方法或用错方法。

注意
控制接口粒度,接口不能太小,太小会导致系统中接口泛滥,不利于维护。
太大不灵活,一般而言,接口中仅包含为某一类用户定制的方法即可,不应该强迫实现类依赖那些他们不用的方法。

合成复用原则

优先使用对象组合,而不是继承来达到复用的目的。

通常类的复用分为继承复用和合成复用两种,继承复用虽然有简单和易实现的优点,但它也存在以下缺点。
a)继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
b)子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。

采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点。
a)它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
b)新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口。

实现:比如大雁会飞,大雁有一双翅膀的引用,具体怎么飞,交给翅膀,往上飞还是向下飞,加速还是减速,只需要传递信息给翅膀即可。

迪米特原则

在设计系统时,应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应该发生任何直接的相互作用,如果其中一个对象需要调用另一个对象的方法,可以通过“第三者”转发这个调用。

简而言之,就是通过引入一个合理的“第三者”来降低现有对象之间的耦合度。
通俗比喻:不要和“陌生人”说话(Don’t talk to strangers)、只与你的直接朋友通信(Talk only to your immediate friends)等
那么他的朋友是谁呢,有以下几类,否则就是陌生人
1)当前对象本身(this)。
2)以参数形式传人到当前对象方法中的对象
3)当前对象的成员对象。
4)如果当前对象的成员对象是一个集-合,那么集-合中的元素也都是朋友。
5)当前对象所创建的对象。

优点
如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易。
应用迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。一个对象的改变不会给太多其他对象带来影响。

实现
在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,越有利于复用;
每一个类都应当尽量降低其成员变量和成员函数的访问权限;
在类的设计上,只要有可能,一个类型应当设计成不变类;
在对其他类的引用上,一个对象对其他对象的引用应当降到最低。

总结

单一职责原则告诉我们实现类要职责单一;
里氏替换原则告诉我们不要破坏继承体系;
合成复用原则告诉我们优先使用组合而不是继承;
依赖倒置原则告诉我们要面向接口编程;
接口隔离原则告诉我们在设计接口的时候要精简单一;
迪米特法则告诉我们要降低耦合;
开闭原则是总纲,要对扩展开放,对修改关闭。

GoF二十三种设计模式

创建型模式(五种)

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
工厂模式(Factory Pattern)
抽象工厂模式(Abstract Factory Pattern)
单例模式(Singleton Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)

结构型模式(七种)

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
适配器模式(Adapter Pattern)
装饰器模式(Decorator Pattern)
代理模式(Proxy Pattern)
外观模式(Facade Pattern)
桥接模式(Bridge Pattern)
组合模式(Composite Pattern)
享元模式(Flyweight Pattern)

行为型模式(十一种)

这些设计模式特别关注对象之间的通信。
策略模式(Strategy Pattern)
模板模式(Template Pattern)
观察者模式(Observer Pattern)
迭代器模式(Iterator Pattern)
责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
备忘录模式(Memento Pattern)
状态模式(State Pattern)
访问者模式(Visitor Pattern)
中介者模式(Mediator Pattern)
解释器模式(Interpreter Pattern)

游戏中的设计模式

地址:https://gpp.tkchu.me
作者:Bob Nystrom

基础设计模式
0、设计模式应用
除非确信代码必需存在灵活性,否则不要浪费时间用于抽象和解耦;
开发过程中对性能的思考和设计,要推迟那些降低灵活性、底层的、详尽的优化;
尽快探索设计空间,但不要太快成型,降低灵活扩展性;
以后要删除的代码不要浪费时间去整理得很整洁;

1、命令模式
把玩家和AI的指令做成命令流(用队列的方式),调用的时候只需要传入被控制角色参数即可——编程语言有闭包直接用闭包,没闭包建命令类。

2、享元模式
将能够共享的数据(例如纹理),做成单独的类,用API调用,提供共享数据和使用数据的实例列表和实例的差异化参数来调用,相同实例只需创建一次,就能在多处使用(地形系统),常用于GPU渲染。

3、观察者模式
发送消息通知对消息感兴趣的对象,不用关心谁接收到了通知(由外部代码控制谁接收通知)。观察者(例如成就系统的某一个成就)接收通知,被观察者(例如可被观察的物理模块)有一个观察者集合(如果需要在观察者类中添加状态,可以用链表),用于发送通知。C#中的event。

4、原型模式
使用特定的原型实例来创建特定种类的对象,并通过拷贝原型来创建新的对象。常用于怪物生成等游戏数据建模任务。

5、单例模式
确保一个类只有一个实例,并为其提供一个全局访问入口。

6、状态模式
允许一个对象在其内部状态改变时改变自身的行为,对象看起来好像是在修改自身类(有限状态机、并发状态机、层次状态机、下推自动机),常用于处理射击游戏主角的状态、游戏AI(行为树和规划系统)等。

序列型模式
1、双缓冲模式
用于解决状态在被修改的同时被读取的问题(周期性地交换两个缓冲区的引用)。
2、游戏循环模式
实现用户输入和处理器速度在游戏进行时间上的解耦。
3、更新方法模式
一系列几乎是相互独立的游戏对象需要同步运转,对象的行为与时间相关时用。

行为型模式
1、字节码
游戏引擎加载数据(模组)——解释器模式
2、沙盒模式
基类用于隐藏游戏引擎实现细节。
3、类型对象模式
当需要定义一系列不同的“种类”,但不想硬编码进类型系统(不知道将来会有什么类型),避开子类继承,保持多态灵活性。

解耦型模式
1、组件模式
单一实体横跨了多个域。每个域的代码都独立地放在组件类中,实体本身可以简化为这些组件的容器。对于庞大的类的解耦。例如unity3d的GameObject类的设计就是如此。
2、事件队列
对消息或事件的发送与受理进行时间上的解耦,例如窗体程序。
3、服务定位器
为某服务(特别是随时要被访问的服务,如游戏音频)。

优化型模式
1、数据局部性
通过合理组织数据,利用CPU的多级缓存机制来加快内存的访问速度(避免缓存未命中、分支预测失准、流水线停顿)。
2、脏标记模式
将工作推迟到必要时进行。例如缓存一些物体的世界变换,并用一个标记它是否过期,可以减少CPU的计算。
3、对象池
使用固定的对象池重用对象,取代单独地分配和释放对象。例如例子系统。让游戏能通过浸泡测试(防止内存扩张和泄露)
将相同类型的对象在内存上整合,能利用好CPU的缓存区提高效率。
4、空间分区模式
将数据存储在根据位置组织的数据结构中来高效地定位它们。

参考:
https://zhuanlan.zhihu.com/p/375287900
https://developer.unity.cn/projects/64a2d7b1edbc2a0ddca627bb
https://github.com/QianMo/Unity-Design-Pattern

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

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

相关文章

C++ | 仿函数

仿函数的用法 在C语言时期,如果想要实现回调函数或者是函数参数需要传入函数,通常是用的函数指针。而在C中,我们一般用仿函数来平替。 仿函数,又叫函数对象。虽然名字叫仿函数,但本质上就是一个重载了 operator() 的类…

车载通信架构 —— DDS协议介绍

车载通信架构 —— DDS协议介绍 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和…

leetcode解题思路分析(一百四十九)1297 - 1304 题

子串的最大出现次数 给你一个字符串 s ,请你返回满足以下条件且出现次数最大的 任意 子串的出现次数: 子串中不同字母的数目必须小于等于 maxLetters 。 子串的长度必须大于等于 minSize 且小于等于 maxSize 。 首先能想到的是从MinSize开始遍历查找&am…

Linux网络监控工具 - iftop

iftop 是一个基于 libpcap 库的网络流量监控工具。它通过监听指定网络接口上的数据包,并分析这些数据包的源地址、目标地址、源端口、目标端口、协议等信息,从而实时显示网络流量的相关统计信息。 安装 在大多数Linux发行版中,您可以使用包管…

计算机竞赛 行人重识别(person reid) - 机器视觉 深度学习 opencv python

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习行人重识别(person reid)系统 该项目…

CSShas伪类选择器案例附注释

<!DOCTYPE html> <html lang="en"> <head><meta charset

配置文件生成器-秒杀SSM的xml整合

配置文件生成器-秒杀SSM的xml整合 思路&#xff1a; 通过简单的配置&#xff0c;直接生成对应配置文件。 maven坐标 <dependencies><!-- 配置文件生成 --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker<…

洛谷1631 序列合并(优先队列)

题目描述 有两个长度为 N 的单调不降序列 ,A,B&#xff0c;在 A,B 中各取一个数相加可以得到 N2 个和&#xff0c;求这 N2 个和中最小的 N 个。 输入格式 第一行一个正整数 N&#xff1b; 第二行 N 个整数 1…A1…N​。 第三行 N 个整数 1…B1…N​。 输出格式 一行 N 个…

理解docx格式5

数字与级 在numbering元素的<w:abstractNum>里面定义,用<w:num>在数字部分内创建元素. <w:numbering> <w:abstractNum w:abstractNumId"0"> <抽象数字/> <w:nsid w:val"099A081C"/> <w:multiLevelType w:val&quo…

maven 初学

1. maven 安装 配置安装 路径 maven 下载位置: D:\software\apache-maven-3.8.6 默认仓库位置: C:\Users\star-dream\.m2\repository 【已更改】 本地仓库设置为&#xff1a;D:\software\apache-maven-3.8.6\.m2\repository 镜像已更改为阿里云中央镜像仓库 <mirrors>…

Kubernetes概述架构与工作流程简述

文章目录 Kubernetes概述Kubernetes优势Kubernetes 集群组件控制平面组件Node 组件 Kubernetes工作流程下期预告 Kubernetes概述 Kubernetes 是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;可促进声明式配置和自动化。 Kubernetes 拥…

简易版Pycharm(2023)+Conda开发环境配置教程

困 扰 不知道为什么&#xff0c;自从Pycharm更新了新的版本以后&#xff0c;在Pycharm中为项目工程配置Python解释器环境时&#xff0c;总是不能像以前那么方便。 比如&#xff0c;当前Conda中有十个不同的开发环境&#xff0c;每个环境一个名称&#xff0c;比如&#xff0c;p…

小程序实现人脸识别功能

调用api wx.startFacialRecognitionVerify 第一步: // 修改方法expertUpdate() {wx.startFacialRecognitionVerify({name: _this.registerForm.realName, //身份证名称idCardNumber: _this.registerForm.idCard, //身份证号码checkAliveType: 1, //屏幕闪烁(人脸核验的交互…

VB.NET vs. VB6.0:现代化编程语言 VS 经典老旧语言

目录 ​.NET背景&#xff1a; 特点: VB6.0背景&#xff1a; 特点: 两者之间的不同: 总结: 升华: .NET背景&#xff1a; VB.NET一种简单&#xff0c;现代&#xff0c;面向对象计算机编程语言&#xff0c;有微软开发&#xff0c;VB.NET是一种基于.NET Framework的面向对象…

golang gin——中间件编程以及jwt认证和跨域配置中间件案例

中间件编程jwt认证 在不改变原有方法的基础上&#xff0c;添加自己的业务逻辑。相当于grpc中的拦截器一样&#xff0c;在不改变grpc请求的同时&#xff0c;插入自己的业务。 简单例子 func Sum(a, b int) int {return a b }func LoggerMiddleware(in func(a, b int) int) f…

docker compose 管理应用服务的常用命令

一 、docker compose 是什么 Docker Compose是一个用来管理多个关联容器的工具&#xff0c;可以根据配置文件自动构建、管理、编排一组容器。 Docker Compose语境下的“服务”是指一组容器共同构成的一个应用服务后端。 Docker Compose语境下的“项目”是由一个或多个应用服务…

【C++设计模式之观察者模式:行为型】分析及示例

简介 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生变化时&#xff0c;所有依赖它的对象都能够自动收到通知并更新。 描述 观察者模式由两个核心件组成&#xff1…

来单提醒/客户催单 ----苍穹外卖day9

来单提醒 需求分析 代码开发 注意:前端请求的并不是8080端口;而是先请求Nginx,Nginx进行反向代理以后转发到8080端口 这段代码首先创建了一个orders类用于更新订单状态 并且在更新状态后使用websocket发送给后端提醒 将信息放在map后,使用json的string化方式传给一个接收对象,…

类 ChatGPT 模型存在的局限性

尽管类ChatGPT模型经过数月的迭代和完善&#xff0c;已经初步融入了部分领域以及人们的日常生活&#xff0c;但目前市面上的产品和相关技术仍然存在一些问题&#xff0c;以下列出一些局限性进行详细说明与成因分析&#xff1a; 1&#xff09;互联网上高质量、大规模、经过清洗…

【广州华锐互动】动物解剖学AR互动学习平台

增强现实&#xff08;AR&#xff09;是一种将虚拟信息叠加到现实世界中的技术。通过智能手机、平板电脑或AR眼镜等设备&#xff0c;AR技术可以创建出逼真的虚拟物体&#xff0c;这些物体可以与现实世界的环境相互交互。 AR技术在教育领域的应用非常广泛&#xff0c;包括历史、科…