游戏开发浅谈游戏开发中常见的设计原则

马三小伙儿 马三小伙儿     2022-09-03     637

关键词:

  俗话说得好:“设计模式,常读常新~”。的确,每读一遍设计模式都会有些新的体会和收获。马三不才,才读了两遍设计模式(还有一遍是在学校学的),属于菜鸟级别的。这次准备把阅读设计模式的想法记录下来,并且把设计模式应用在Unity游戏开发上,做些小案例。

什么是设计模式

  每一种模式都在说明某种一再出现的问题,并描述解决方法的核心,之后让你能够举一反三,从而解决数个类似的问题。每一种设计模式除了按照“面向对象的设计原则”加以分析设计之外,还满足:”解决一再出现的问题“、”解决问题的方案和问题核心的关键点“、”可以重复利用解决方案“这样几个要求。

  通过引入”模式“的概念,以经验积累的方式,将一些经常用来解决特定问题的”类设计“、”对象组装“加以整理并定义成一种”设计模式“。而这些设计模式让开发者在以后遇到相同的问题时,可以从中找出对应的解决方案直接使用,不必再过多地思考如何设计分析。这样不但可以减少不必要的时间花费,还可以加强软件的”稳定性“和”可维护性“。

游戏开发设计中的常见7大设计原则

  虽然标题写的是”游戏开发设计中的常见7大设计原则“,其实这些原则本来就是适用于普遍性的面向对象设计。如果软件设计人员能够充分了解这些设计原则并且加以利用,那么就可以让实现出来的系统更加稳定、容易维护、具有更好的拓展性。

单一职责原则(SRP)

  这个原则强调的是”当设计封装一个类时,该类应该只负责一件事“。当然,这与在类抽象化的过程中,对于该类所负责的功能有关。一个类应该只负责系统中的一个单独功能的实现,但是对于功能的划分和归属,通常也是开发过程中最困扰设计人员的问题。设计人员在一开始的时候不太容易遵循这个原则,会在项目开发的过程中,不断地向同一个类上添加功能,最后导致类过于庞大、接口过于复杂后才会发现这个问题,最后可能让整个项目过度依赖这个类,使得项目失去弹性。

  但是,只要通过不断地进行”类重构“,将类中与实现相关功能的部分抽取出来,另外封装成新的类,之后利用组合的方式,将新增的类加入到原有的类中,慢慢地就能符合类单一职责化的要求了,即项目中每一个类都只负责单一功能的实现。

开闭原则(OCP)

  一个类应该”对拓展开放,对修改封闭“。何为对拓展开放对修改封闭呢?其实这里提到的类指的是实现系统某项功能的类。而这个功能的类,除非是修正错误,否则,当软件的开发流程进入“完工测试期”或者“上市维护期”时,对于已经测试完成或者已经上线运行的功能,就应该“关闭对修改的需求”,也就是不能再修改这个类的任何接口或者实现。

  但是,当增加系统功能的需求发生的时候,又不能置之不理,所以也必须对“功能的增加保持开放”。为了满足这个原则的要求,系统分析时就要朝向“功能接口化”的方向进行设计,将系统功能的“操作方法”向上提升,抽象化为接口,将“功能的实现”向下移到子类中。因此,在面对增加系统功能的需求时,就可以使用“增加子类”的方法来满足。具体的实现方式是:重新实现一个新的子类,或者继承就得实现类,并在新的子类中实现新增的系统功能。这样,对于旧系统的功能实现就可以保持不变(封闭),同时又对功能的新增需求保持开放。

里氏替换原则(LSP)

  这个原则指的是“子类必须能够替换父类”。如果按照这个设计原则去实现一个有多层继承的类群组,那么其中的父类通常是“接口”或者“可被继承的类”。父类中一定包含了可被子类重新实现的方法,而客户端使用的操作接口也是由父类来定义的。客户端在使用的过程中,必须不能使用到“对象强制转型成子类”的语句,客户端也不应该知道,目前正在使用的对象是哪一个子类实现的。至于使用哪个子类对象来代替父类对象,则是由类本身的对象产生机制来决定,外籍无法得知。里氏替换原则基本上也是对于开放——封闭原则提供了一个实现的法则,说明如何设计才能保持正确的需求开放。

依赖倒置原则(DIP)

  这个原则包含了两个主题:

  • 高层模块不应该依赖于低层模块,两者都应该依赖于抽象概念;
  • 抽象接口不应该依赖于实现,而实现应该依赖于抽象接口。

  从生活中举例来解释第一个原则主题(高层模块不应该依赖于低层模块),两者都应该依赖于抽象,可能会比单纯使用软件设计来解释更为容易,所以下面就以汽车为例进行说明。

  汽车与汽车引擎就是一个很明显违反这个原则的例子:汽车就是所谓的高层模块,当要组装一台汽车时,需要有不同的低层模块进行配合才能完成,如引擎、传统系统、轮胎、汽车骨架等,有了这些低层模块的相互配合才能完成一辆汽车的装配。但是汽车很容易被引擎系统给限定。汽油机的汽车不能加装柴油,柴油机的汽车不能加装汽油。每当汽车要加油的时候,都必须根据引擎来选择不同的加油设施,汽车因为引擎而被限定了加油的品项。虽然这是一个很难去改变的例子,但是在软件系统的设计上,反倒有很多方法可以去避免这个“高层依赖于低层”的问题,也就是将它们之间的关系反转,让低层模块按照高层模块所定义的接口去实现。

  以电脑的组成为例,位于高层的电脑定义了USB接口,而这个接口定义了硬件所需的规格及软件驱动程序的编写规范。只要任何低层模块,如储存卡、手机、U盘、读卡器等设备,凡是符合USB接口规范的,都能加入到电脑中,成为电脑的一部分。通过这个电脑的例子我们大概就可以明白如何由“高层模块定义接口”再由“底层模块遵循这个接口实现”的过程,这个过程可以让他们之前的依赖关系反转。同时,这个反转的过程也说明了第二项原则的含义:“抽象接口不应该依赖于实现,而实现应该依赖于抽象接口”。当高层模块定义了沟通接口以后,与低层模块的沟通就应该只通过接口来进行,在具体实现上,这个接口可能是以一个类的变量或者对象引用来表示的。请注意,在使用这个变量或者对象引用的过程中,不能做任何的类型转换,因为这样就限定了高层模块只能使用某一个底层模块的特定实现。而且,子类在重新实现时,都要按照接口类所定义的方法进行实现,不应该再新增其他方法,不能让高层模块有利用类型转换的方法去调用的机会。

  依赖倒转原则的本质就是通过抽象类(接口或抽象类),使各个类或者模块间实现彼此独立,不互相影响,从而实现模块间的松散耦合。那么我们如何在开发中遵守或者使用这个原则呢,下面是一些建议:

  • 每个类尽量都继承自接口或者抽象类,或者抽象类和接口两者都具备。这是依赖倒转的基本要求,接口和抽象类都是抽象的,有了抽象才能依赖倒转。
  • 变量的显示类型尽量是接口或者抽象类
  • 很多书上说变量的类型一定是接口或者抽象类,其实这样说有点过于绝对了。比如一个工具类一般是不需要接口或者抽象类的。
  • 类要尽量避免从具体的类派生。如果一个项目正处于开发状态,确实不应该有从具体类派生出子类的情况,但这也不是绝对的,因为人都会犯错误,有的时候设计的缺陷在所难免,因此只要继承深度不超过两层都是可以接受的。特别说明的是做项目维护的工程师,基本上可以不考虑这个规则,因为维护工作基本上都是做拓展开发、修复bug。通过一个继承关系,覆盖一个方法就可以修复一个很大的bug,何必在要去继承最高的基类呢?
  • 尽量不要覆盖基类的方法。如果基类是一个抽象类,而且这个方法已经实现了,子类就尽量不要去覆盖。类间依赖的是抽象,覆盖了抽象方法,对依赖的稳定性会产生一定的影响。

接口隔离原则(ISP)

  “客户端不应该被迫使用它们用不到的接口方法。”这个问题一般随着项目开发的进行而越来越明显。当项目中出现了一个负责主要功能的类,而且这个类还必须负责和其他子系统进行沟通时,针对每一个子系统的需求,主要类就必须增加对应的方法。但是,增加越多的方法就等同于增加类的接口的复杂度。因此每当要使用这个类的方法的时候,就要小心翼翼地从中选择正确的方法,无形之中增加了开发和维护的难度。通过“功能的切分”和“接口的简化”可以减少这类问题的发生,或者运用设计模式来重新规划类,也可以减少不必要的操作接口出现在类中。

最少知识原则(LKP)

   当设计实现一个类时,这个类应该越少使用到其它类提供的功能越好。意思是,当这个类能够只靠本身的“知识”去完成功能的话,那么就相应地减少与其他对象“知识”的依赖度。这样的好处就是减少了这个类与其他类的耦合度(即依赖度),换个角度来看,就是增加了这个类被不同项目复用的可能性,提高类的重用性。

少用继承多用组合原则

  当子类继承一个“接口类”后,新的子类就要负责重新实现接口类中所定义的方法,而且不该额外扩充接口,以符合上述多个设计原则的要求。但是,当系统想要扩充或者增加某一项功能时,让子类继承原来的实现类,却也是最容易实现的方式之一。新增的子类在继承父类后,在子类内增加想要扩充的“功能方法”并加以实现,客户端之后就能直接利用子类对象进行新增功能的调用。

  但是对于客户端而言,当下可能只是需要子类所提供的功能,对父类中一些额外方法并不感兴趣,因为这样会增加开发者挑选方法时的难度。例如,“闹钟类”可以利用继承“时钟类”的方式,获得一个“时间功能”的方法,只要子类本身再另外加上“定时提醒”的功能,就能实现“闹钟功能”的目标。当客户端使用“闹钟类”的时候,可能期待的只不过是设定闹钟时间的方法而已,对于取得当前时间的功能并没有迫切的需求。因此,从“时钟父类”继承而来的方法,对于闹钟的用户来说,可能是多余的。

  如果将设计改为在闹钟的类中声明一个类型为时钟类的“类成员”,那么就可以减少不必要的方法出现在闹钟接口上,也可以减少“闹钟类”的客户端对“时钟类”的依赖。另外,在无法使用多重继承的程序设计语言中(Java、C#等),使用组合的方式会比层层继承的方式更加容易理解和维护,并且对于类的封装也有比较好的表现方式。

总结

  以上只是面向对象设计中的7个基本的设计原则,却也是最重要的原则,只有理解了这些基础的原则之后才能继续更深入地学习GOF所提到的23种设计模式。23种设计模式并不是教条式的规则和框架,他们都是解决问题的方法的概念的呈现。一些优秀的设计方案由于种种原因并没有被GOF写入到23种设计模式中,但这并不意味着它不是设计模式。GOF曾说过“没有规定一定要与书中一模一样的架构才能被称为一种模式。”,比如依赖注入和控制反转就是非常好的、应用非常广泛的一种设计方案。

  另外,对于之后的本系列博客一些DEMO工程,将会同步到Github,点我点我

 

作者:马三小伙儿
出处:http://www.cnblogs.com/msxh/p/6921679.html 
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!

unity游戏开发浅谈unity游戏开发中的单元测试

一、单元测试的定义与作用  单元测试定义:单元测试在传统软件开发中是非常重要的工具,它是指对软件中的最小可测试单元进行检查和验证,一般情况下就是对代码中的一个函数去进行验证,检查它的正确性。一个单元测... 查看详情

浅谈开发中常用的设计模式

设计模式在开发中占很重要的地位。在大型项目中使用好设计模式往往会取得事半功倍的效果。本篇博客就介绍下几种在开发中常用到的设计模式。设计原则先看下一些约定俗成的设计原则,其实要遵守以下所有原则很难... 查看详情

移动游戏的精品原则

去年全球网络游戏市场收入达1,011亿美元,中国占246亿美元(约1,789亿元人民币),同比增长25%,超越美国成为“全球游戏玩家之都”。中国玩家的所有游戏支出中,高达93%流向中国公司开发的游戏。其细分领域中,类游戏因其... 查看详情

app开发设计应以人为本!浅谈app交互设计原则

   为什么APP开发设计需要原则?设计原则其实就是对一些设计过程中基于人类的认知规律对设计做出的一些指导性原则,并且对已经成为行业共识的设计经验做个总结,用来指导设计师界定问题、提高效率。  ... 查看详情

浅谈虚拟内存与项目开发中的oom问题

这是【游戏开发那些事】第55篇原创文章中关于Windows平台虚拟内存的部分内容转自知乎用户“南京周润发”内存管理是操作系统中极为核心且重要的内容,也是游戏开发者极为头痛的问题之一。由于游戏在研发中需要加载大... 查看详情

浅谈虚拟内存与项目开发中的oom问题

这是【游戏开发那些事】第55篇原创文章中关于Windows平台虚拟内存的部分内容转自知乎用户“南京周润发”内存管理是操作系统中极为核心且重要的内容,也是游戏开发者极为头痛的问题之一。由于游戏在研发中需要加载大... 查看详情

浅谈虚拟内存与项目开发中的oom问题

这是【游戏开发那些事】第55篇原创文章中关于Windows平台虚拟内存的部分内容转自知乎用户“南京周润发”内存管理是操作系统中极为核心且重要的内容,也是游戏开发者极为头痛的问题之一。由于游戏在研发中需要加载大... 查看详情

手机app游戏开发中常见的5个错误解析

  一款手机游戏的成功,和其开发过程有着密切的关系,在任何一个开发过程中出现的错误,都会影响游戏以后的发展。那么我们在手机游戏的开发过程中常见的错误有哪些呢?我们又该如何避免这个情况的发生呢?一起来看... 查看详情

浅谈面向对象开发原则:高内聚,低耦合

软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分摸块的一个准则就是高内聚低耦合。这是软件工程中的概念,是判断设计好坏的标准,主要是面向OO的设计,主要是看类的内聚性是否高,偶合度是否低.每一... 查看详情

unity项目开发——浅谈设计模式的六大原则(代码片段)

目录前言首先,六大原则是谁?其次,为什么需要学习这六大原则?正文一、单一职责原则示例:因此我们需要进行拆分,根据具体的职能可将其具体拆分如下:Unity单一职责原则二、开闭原则Unity开闭... 查看详情

unity3d游戏开发之c#编程中常见数据结构的比较

一.前言 Unity3D是如今最火爆的游戏开发引擎,它可以让我们能轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型的互动内容。它支持2D/3D游戏开发,据不完全统计,目前国内80%的手机游戏都是用Unity3D开发。由... 查看详情

游戏开发中常用的设计模式

...记住,而且有些设计模式更多的适用于应用程序开发,对游戏项目引擎设计并没有很多的利用价值。根据经验,精挑细选后,笃志在这里记录一些自认为有利用价值的设计模式,以便之后自己设计时使用。一:观察者Observer观察... 查看详情

游戏开发与设计中的“3c”是指什么?

这是【游戏开发那些事】第47篇原创随着国内游戏行业的不断发展,越来越多国外的专业词汇被引入进来。“3C”作为一个比较重要的技术名词至今却仍然被不少游戏从业者所陌生。那么到底什么是3C?他在游戏设计以及... 查看详情

[unity设计模式与游戏开发]七大设计原则(代码片段)

前言我对设计模式的理解是它就好像习武之人的内功,当内功强的人学习各种高深的武功就很得心应手,设计模式不同层次不同阶段的人对它的理解不同,我一直认为设计模式和算法一直是程序员两块非常重要的基本... 查看详情

[unity设计模式与游戏开发]单例模式(代码片段)

前言单例模式是我们最常用的设计模式,面试的时候如果问任何一个开发者设计模式,单例模式估计是脱口而出吧,23中常见的设计模式之中并不是所有设计模式都是很常用的,而单例模式绝对是最常用的那一个... 查看详情

游戏后端游戏服务器端开发的一些建议(转载)

摘要:本文作为游戏服务器端开发的基本大纲,是游戏实践开发中的总结。第一部分专业基础,用于指导招聘和实习考核,第二部分游戏入门,讲述游戏服务器端开发的基本要点,第三部分服务端架构,介... 查看详情

java架构师必须知道的6大设计原则

序言在软件开发中,前人对软件系统的设计和开发总结了一些原则和模式,不管用什么语言做开发,都将对我们系统设计和开发提供指导意义。本文主要将总结这些常见的原则,和具体阐述意义。开发原则面向对象的基本原则(so... 查看详情

怎么使用虚幻4开发游戏?

使用虚幻4开发游戏的过程:1、下载虚幻4引擎。2、准备好游戏资源(美术,模型,音乐等等)。3、把所有资源导入到虚幻4编辑器中。4、使用蓝图或C++进行程序开发(前提需要游戏关卡设计等)。5、虚幻4编辑器中进行游戏打包... 查看详情