目录

一、23种设计模式在Unity实现

Creational Patterns 创建型模式(5种)

工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式

Structural Patterns 结构型模式(7种)

适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

Behavioral Patterns 行为型模式(11种)

策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

二、《游戏编程模式》的Unity实现

Subclass Sandbox Pattern 子类沙盒模式

Type Object Pattern 类型对象模式

Component Pattern 组件模式

Event Queue Pattern 事件队列模式

Game Loop Pattern 游戏循环模式

Service Locator Pattern 服务定位器模式

Data Locality Pattern 数据局部性模式

Dirty Flag Pattern 脏标记模式

Object Pool Pattern 对象池模式


Unity3D中各种设计模式的实践与运用。

  • 目前已经在Unity中实现了《设计模式:可复用面向对象软件的基础》一书中提出的23种设计模式。
  • 每种模式都包含对应的结构实现、应用示例以及图示介绍。类似Naphier/unity-design-patterns的结构,此repo中的每种模式用单独的文件夹分开。每种模式对应的文件夹中包含了名为“Structure”的子文件夹,里面存放的是此模式在Unity中的使用代码的基本框架实现,而另外包含的Example子文件夹中存放的是此模式在Unity中使用的实际示例。每种框架实现或实例示例实现都包含对应的场景,每种模式文件夹中可能包含一个或者多个Example。
  • 《游戏编程模式》一书中介绍的常用游戏设计模式的Unity版实现也有部分实现。

一、23种设计模式在Unity实现

Creational Patterns 创建型模式(5种)

  • Prototype Pattern 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
  • Singleton Pattern 单例模式:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
  • Abstract Factory Pattern 抽象工厂模式:提供一个接口,用于创建相关或者依赖对象的家族,而不需要指定具体的实现类。
  • Builder Pattern 建造者模式:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
  • Factory Method Pattern 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

Structural Patterns 结构型模式(7种)

  • Adapter Pattern 适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • Bridge Pattern 桥接模式:将抽象和实现解耦,使得两者可以独立地变化。
  • Composite Pattern 组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
  • Decorator Pattern 装饰模式:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
  • Facade Pattern 外观模式:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。外观模式提供一个高层次的接口,使得子系统更易于使用。
  • Flyweight Pattern 享元模式:使用共享对象可有效地支持大量的细粒度的对象。
  • Proxy Pattern 代理模式:为其他对象提供一种代理以控制对这个对象的访问。

Behavioral Patterns 行为型模式(11种)

  • Command Pattern 命令模式:命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象,同时支持可撤消的操作。
  • State Pattern 状态模式:当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。
  • Observer Pattern 观察者模式:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
  • Chain of Responsibility Pattern 责任链模式:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
  • Mediator Pattern 中介者模式:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
  • Interpreter Pattern 解释器模式:给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
  • Iterator Pattern 迭代器模式:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
  • Memento Pattern 备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
  • Strategy Pattern 策略模式:定义一组算法,将每个算法都封装起来,并且使它们之间可以互换
  • Template Method Pattern 模板方法模式:定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
  • Visitor Pattern 访问者模式:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

二、《游戏编程模式》的Unity实现

Subclass Sandbox Pattern 子类沙盒模式

意义

使用基类提供的操作集合来定义子类中的行为。

模式描述

一个基类定义了一个抽象的沙盒方法和一些预定义的操作集合。通过将它们设置为受保护的状态以确保它们仅供子类使用。每个派生出的沙盒子类根据父类提供的操作来实现沙盒函数。

使用情形

沙盒模式是运用在多数代码库里、甚至游戏之外的一种非常简单通用的模式。如果你正在部署一个非虚的受保护方法,那么你很可能正在使用与之类似的模式。沙盒模式适用于以下情况:

  • 你有一个带大量子类的基类。
  • 基类能够提供所有子类可能需要执行的操作集合。
  • 在子类之间有重叠的代码,你希望在它们之间更简便地共享代码。
  • 你希望使这些继承类与程序其他代码之间的耦合最小化。

Type Object Pattern 类型对象模式

意义

通过创建一个类来支持新类型的灵活创建,其每个实例都代表一个不同对象类型。

两个类,可以实现无限的种类

模式描述

定义一个类型对象类和一个持有类型对象的类。每个类型对象的实例表示一个不同的逻辑类型。每个持有类型对象类的实例引用一个描述其类型的类型对象。

实例数据被存储在持有类型对象的实例中,而所有同概念类型所共享的数据和行为被存储在类型对象中。引用同一个类型对象的对象之间能表示出“同类”的特性。这让我们可以在相似对象集合中共享数据和行为,这与类派生的作用有几分相似,但却无需硬编码出一批派生类。

使用情形

当你需要定义一系列不同“种类”的东西,但又不想把那些种类硬编码进你的类型系统时,本模式都适用。尤其其是当下面任意一项成立时:

  • 你不知道将来会有什么类型(例如,我们的游戏是否需要指出包含怪物新种类的资料包下载?)
  • 你需要在不重新编译或修改代码的情况下,修改或添加新的类型。

Component Pattern 组件模式

意义

允许一个单一的实体跨越多个不同域而不会导致耦合。

模式描述

A single entity spans multiple domains. To keep the domains isolated, the code for each is placed in its own component class. The entity is reduced to a simple container of components. 
单一实体横跨了多个域。为了能够保持域之间相互隔离,每个域的代码都独立地放在自己的组件类中。实体本身则可以简化为这些组件的容器。

使用情形

组件最常见于游戏中定义实体的核心类,但是它们也能够用在别的地方。当如下条件成立时,组件模式就能够发挥它的作用:

  • 你有一个涉及多个域的类,但是你希望这些域保持相互解耦。
  • 一个类越来越庞大,越来越难以开发。
  • 你希望定义许多共享不同能力的对象,但采用继承的办法却无法令你精确地重用代码。

Tips

Unity引擎的主要设计正是围绕组件模型来进行的。

Event Queue Pattern 事件队列模式

意义

对消息或事件的发送与受理进行时间上的解耦。

模式描述

事件队列是一个按照先进先出顺序存储一系列通知或者请求的队列。发出通知时系统会将该请求置入队列并返回,请求处理器随后从事件队列中获取并处理这些请求。请求可由处理器直接处理或转交给对其感兴趣的模块。这一模式对消息的发送者与受理者进行了解耦,使消息的处理变得动态且非实时。

使用情形

如果你只是想解耦接收者和发送者,像观察者模式和命令模式都可以用较小的复杂度来进行处理。在需要解耦某些实时的内容时才建议使用事件队列。

不妨用推和拉来的情形来考虑。有一块代码A需要另一块代码B去做些事情。对A自然的处理方式是将请求推给B。

同时,对B自然的处理方式是在B方便时将请求拉入。当一端有推模型另一端有拉模型时,你就需要在它们间放一个缓冲的区域。 这就是队列比简单的解耦模式多出来的那一部分。

队列给了代码对拉取的控制权——接收者可以延迟处理,合并或者忽视请求。发送者能做的就是向队列发送请求然后就完事了,并不能决定什么时候发送的请求会受到处理。而当发送者需要一些回复反馈时,队列模式就不是一个好的选择。

Game Loop Pattern 游戏循环模式

意义

游戏循环模式,实现游戏运行过程中对用户输入处理和时间处理的解耦。

模式描述

游戏循环模式:游戏循环在游戏过程中持续运转。每循环一次,它非阻塞地处理用户的输入,更新游戏状态,并渲染游戏。它跟踪流逝的时间并控制游戏的速率。

游戏循环将游戏的处理过程和玩家输入解耦,和处理器速度解耦,实现用户输入和处理器速度在游戏行进时间上的分离。

游戏循环也许需要与平台的事件循环相协调。如果在操作系统的高层或有图形UI和内建事件循环的平台上构建游戏,那就有了两个应用循环在同时运作,需要对他们进行相应的协调。

使用情形

任何游戏或游戏引擎都拥有自己的游戏循环,因为游戏循环是游戏运行的主心骨。

Unity已经内建了游戏循环模式,即Update( )方法。

Service Locator Pattern 服务定位器模式

意义

提供服务的全局接入点,而不必让用户和实现它的具体类耦合。

模式描述

的服务提供者实现这个接口。一个单独的服务定位器通过查找一个合适的提供器来提供这个服务的访问,它同时屏蔽了提供器的具体类型和定位这个服务的过程。

使用情形

一般通过使用单例或者静态类来实现服务定位模式,提供服务的全局接入点。 服务定位模式可以看做是更加灵活,更加可配置的单例模式。如果用得好,它能以很小的运行时开销,换取很大的灵活性。相反,如果用得不好,它会带来单例模式的所有缺点以及更多的运行时开销。 使用服务定位器的核心难点是它将依赖,也就是两块代码之间的一点耦合,推迟到运行时再连接。这有了更大的灵活度,但是代价是更难在阅读代码时理解其依赖的是什么

Tips

服务定位器模式在很多方面和单例模式非常相近,所以值得考虑两者来决定哪一个更适合你的需求。

Unity引擎把这个模式和组件模式结合起来,并使用在了GetComponent()方法中。

Data Locality Pattern 数据局部性模式

意义

通过合理组织数据利用CPU的缓存机制来加快内存访问速度。

模式描述

现代的CPU有缓存来加速内存读取,其可以更快地读取最近访问过的内存毗邻的内存。基于这一点,我们通过保证处理的数据排列在连续内存上,以提高内存局部性,从而提高性能。

为了保证数据局部性,就要避免的缓存不命中。也许你需要牺牲一些宝贵的抽象。你越围绕数据局部性设计程序,就越放弃继承、接口和它们带来的好处。没有银弹,只有权衡。

使用情形

使用数据局部性的第一准则是在遇到性能问题时使用。不要将其应用在代码库不经常使用的角落上。 优化代码后其结果往往更加复杂,更加缺乏灵活性。

就本模式而言,还得确认你的性能问题确实由缓存不命中而引发的。如果代码是因为其他原因而缓慢,这个模式自然就不会有帮助。

简单的性能评估方法是手动添加指令,用计时器检查代码中两点间消耗的时间。而为了找到糟糕的缓存使用情况,知道缓存不命中有多少发生,又是在哪里发生的,则需要使用更加复杂的工具—— profilers。

组件模式是为缓存优化的最常见例子。而任何需要接触很多数据的关键代码,考虑数据局部性都是很重要的。

Dirty Flag Pattern 脏标记模式

意义

将工作推迟到必要时进行以避免不必要的工作。

模式描述

一组原始数据随时间变化。一组颜色数据经过一些代价昂贵的操作由这些数据确定。一个脏标记跟踪这个衍生数据是否和原始数据同步。它在原始数据改变时被设置。如果它被设置了,那么当需要衍生数据时,它们就会被重新计算并且标记被清除。否则就使用缓存的数据。

使用情形

就像其他优化模式一样,此模式会增加代码复杂度。只在有足够大的性能问题时,再考虑使用这一模式。

脏标记在这两种情况下适用:

  • 当前任务有昂贵的计算开销
  • 当前任务有昂贵的同步开销。 若满足这两者之一,也就是两者从原始数据转换到目标数据会消耗很多时间,都可以考虑使用脏标记模式来节省开销。

若原始数据的变化速度远高于目标数据的使用速度,此时数据会因为随后的修改而失效,此时就不适合使用脏标记模式。

Object Pool Pattern 对象池模式

意义

使用固定的对象池重用对象,取代单独地分配和释放对象,以此来达到提升性能和优化内存使用的目的。

模式描述

定义一个保持着可重用对象集合的对象池类。其中的每个对象支持对其“使用(in use)”状态的访问,以确定这一对象目前是否“存活(alive)”。在对象池初始化时,它预先创建整个对象集合(通常为一块连续堆区域),并将它们都置为“未使用(not in use)”状态。

当我们想要创建一个新对象时,就向对象池请求。它将搜索到一个可用的对象,将其初始化为“使用中(in use)”状态并返回给你。当该对象不再被使用时,它将被置回“未使用(not in use)”状态。使用该方法,对象便可以在无需进行内存或其他资源分配的情况下进行任意的创建和销毁。

使用情形

此模式被广泛地应用于游戏中的可见物体,如游戏实体对象、各种视觉特效。但是它也可在非可见的数据结构上使用,比如当前播放的声音。

满足以下情况可以使用对象池:

  • 需要频繁创建和销毁对象时。
  • 对象大小一致时。
  • 在堆上分配对象缓慢或者会导致内存碎片时。
  • 每个对象都封装了很昂贵且又可以重用的资源,如数据库、网络的连接。

Unity实现:23种设计模式、《游戏编程模式》相关推荐

  1. 【Unity与23种设计模式】访问者模式(Visitor)

    GoF中定义: "定义一个能够在一个对象结构中对于所有元素执行的操作.访问者让你可以定义一个新的操作,而不必更改到被操作元素的类接口." 暂时没有完全搞明白 直接上代码 //访问者 ...

  2. 23种设计模式7_代理模式之一静态代理

    23种设计模式7_代理模式之一静态代理 1 基本介绍 代理模式:为其他对象提供一种代理以控制对这个对象的访问 代理模式也叫委托模式,它是一项基本设计技巧.许多其他的模式,如状态模式.策略模式.访问者模 ...

  3. 实践GoF的23种设计模式:建造者模式

    本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:建造者模式>,作者: 元闰子. 简述 在程序设计中,我们会经常遇到一些复杂的对象,其中有很多成员属性,甚至嵌套着多个复杂的对象 ...

  4. 23种设计模式——装饰者模式

    文章目录 23种设计模式--装饰者模式 1.装饰者模式概述 2.装饰者模式的结构 3.装饰者模式的实现 4.装饰者模式的应用场景 23种设计模式--装饰者模式 1.装饰者模式概述 背景 有些人为了早上 ...

  5. 【Go实现】实践GoF的23种设计模式:命令模式

    上一篇:[Go实现]实践GoF的23种设计模式:代理模式 简单的分布式应用系统(示例代码工程):https://github.com/ruanrunxue/Practice-Design-Patter ...

  6. 23种设计模式之命令模式和策略模式的区别

    文章目录 概述 命令模式 策略模式 相同点 总结 概述 命令模式和策略模式确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的 ...

  7. 23种设计模式之代理模式

    文章目录 代理模式的定义与特点 代理模式的结构与实现 模式的结构 模式的实现 代理模式的应用场景 代理模式的应用实例 代理模式的扩展 代理模式分类 静态代理 动态代理 在有些情况下,一个客户不能或者不 ...

  8. 23种设计模式----中介者模式----行为型模式

    中介者模式 1.什么是中介者模式 2.中介者模式的角色 3.例子 3.1 项目结构 3.2 共同实体 3.3 抽象的中介者 3.4 抽象的被中介者 3.5 具体的中介者 3.6 具体的被中介者 3.7 ...

  9. 2.5万字详解23种设计模式—创建型模式(简单工厂、工厂方法、抽象工厂、单例-多线程安全详解、建造者、原型)的详细解读、UML类图

    本文简述了各大设计模式,并通过UML和代码详细说明.本文大约共 2.5W 字,建议收藏.下方是本文的目录: 一.设计模式的认识 二.设计模式的分类 根据其目的 根据范围 三.设计模式的优点 四.设计模 ...

  10. 23种设计模式-行为型模式-观察者模式

    概述 它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应.在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多 ...

最新文章

  1. Linux 服务器日志文件查找技巧精粹
  2. python画图代码turtle-使用Python的turtle模块画图的方法
  3. centos 7 安装docker 并设置阿里云镜像仓库
  4. 宇宙第一 IDE Visual Studio 2019 正式发布
  5. mysql象限和投影_Camera类之orthographic-摄像机投影模式(第100篇随笔)
  6. 问问大家作为大数据总监,刚刚到一家新单位,怎么开展工作比较好?
  7. 大道至简第7,8章读后感
  8. mysql+只读参数_mysql只读变量
  9. 微信小程序 PDF下载打印
  10. MySQL 高级 - 语法 - if判断
  11. 一分钟了解react
  12. 如何做一个国产数据库(六) 网络传输 nodejs做测试客户端
  13. setuptools find_packages
  14. c# mysql数据集_C#第四次作业:MySQL数据库及C#操作MySQL数据库
  15. 外星人到底在哪?普利茅斯大学新建AI寻系外生命系统
  16. vs2008打开aspx文件时设计界面死机情况的解决
  17. 2021年CKA考试真题(二)
  18. HDU-1814 Peaceful Commission (2-SAT暴力模板 暴力染色+字典序最小)
  19. 大厂Java岗春招必看:论一个面渣逆袭之路上必学得那些知识点
  20. PFSO-T5,一种OLED材料

热门文章

  1. 发票识别+发票真伪查验接口
  2. spring boot 是如何利用jackson进行序列化的?
  3. 人和人的相遇,是必然还是偶然
  4. power bi数据分析_Power BI数据模型:使用关系
  5. iView UI库解决基于vue.js解决table中this的指向问题
  6. steam搬砖项目基础分析,月入8000+(详细教程)
  7. 某程序员哀叹:月薪四五万,却每天极度焦虑痛苦,已有生理性不适,又不敢裸辞,该怎么办?
  8. 早知道失业这么难,我当初就不该裸辞
  9. Linux lvm分区扩容、给sda2扩容
  10. SuanCloud区块链可信数据平台