算法、数据结构、与设计模式等在游戏开发中的运用 (一):单例设计(Singleton Design)

作者: Compasslg 李涵威

1. 什么是单例设计(Singleton Design)

在学校学习面向对象编程中的一些常用的设计模式时,我第一次系统的接触到了单例设计(Singleton Design),或者说单例设计模式。所谓设计模式(Design Pattern),指的是在软件开发中针对一些常见问题提出的可复用的解决方式;而单例设计便是针对在面向对象编程中一些只会被实例化一次、或只允许一个实例(instance)存在的类(class)而出现的设计模式。这种对象/实例通常是作为工程中一个全局管理的存在,因此他们会在整个工程的各个角落被调用。由于在面向对象编程的设计中你往往需要通过储存一个对象的地址来随时调用其中的方法和数据,这便可能会造成同一个对象的地址被储存很多次的情况。

在单例设计模式中,你可以通过将单例目标类的构造器(Constructor)设置为private类型使该类无法在外部被实例化,然后在这个类的内部实例一个自己的对象并将其储存在一个静态变量中。同时,你也可以写一个公开的静态getter方法来作为获取和调用这个单例的方式。如此这般,通过使用单例设计模式,你便可以实现一个全局有且只有一个实例的类。具体实现方式我会在下一个部分举例说明。

2. 如何使用单例设计 (Java 范例)

Java是单例设计最常被应用的语言。一个最典型的例子便是java.lang.Runtime中的Runtime class. 该类无法被实例,你可以通过其中的静态方法Runtime.getRuntime()来调用他的单例 object。

除此之外,在软件和游戏开发中还有很多的功能可以利用单例设计实现,以下便是一个用Java通过单例设计实现的可能被应用在游戏和软件中的音频管理器(AudioManager)的简单模型:

/**===========================================
这是一个在游戏中管理音频文件的类,有且只有存在一个。
因此使用单例设计模式。
*===========================================*/
class AudioManager {
// 设置为private,外部便不能再修改这个单例。
private static instance; // 单例中实际储存的内容。这里使用的数据类型只是作为该单例的应用背景(context),仅供参考,在AudioManager中具体要用什么数据类型来储存音频资料应视情况而定
private HashMap<String, AudioClip> clips; // ... 此处略过其他AudioManager可能需要的变量 ... // private 构造器,无法被外部调用
private AudioManager(){
clips = new HashMap<String, AudioClip>();
// ... 此处略过其他可能需要初始化的东西
} // 单例的 Getter。会且只会实例一个该类的实例。
// 如果担心第一次调用时的速度影响,可以在loading的时候统一将单例设计的类的getInstance方法调用一次
public static AudioManager getInstance(){
// 实例化如果此前没有实例
if (instance == null){
instance = new AudioManager();
}
return instance;
} // 播放一段音频的方法
public void playAudioClip(String clipName){
clips.get(clipName).play();
}
}

以下是调用方法:

public static void main(String[] args){
AudioManager.getInstance().playAudioClip("BGM");
}

3. 游戏开发中的运用 (Unity)

在游戏开发过程中,我们常常会需要应用到一些负责全局管理的并且只会同时存在一个实例的类,例如上面提到的AudioManager,还有负责管理游戏状态或界面的StateManager和SceneManager,我自己写游戏也经常会写一个负责数据管理的类DataManager。这些类都是有且只有一个实例存在,都可以通过 Part 2 中的方法依样画葫芦实现和调用,这里就不复述了。

在使用Unity开发游戏时,我们往往会要用到一个GameController。在我接触单例设计之前,我都会选择在要用到他的地方存一个变量,然后通过在编辑器中把它拖到inspector,或者使用

gameController = GameObject.FindWithTag("GameController");

来找到它。久而久之,这样不但使代码变得混乱且重复,在速度上和内存空间上也给我一种很浪费的感觉。这个时候,我们可以利用Singleton Design思想,在GameController中加一个静态变量

public class GameController : MonoBehaviour {

	private static GameController instance;
void Awake(){
// ... 省略其他初始化相关代码 ...
instance = this;
} public static GameController GetInstance(){
return instance;
}
}

这样,虽然这个类是绑定Unity中的GameObject被实例的而并非按照此前提到的通过private constructor的方法生成的单例,我们依然可以利用单例设计中的部分思想来使他调用起来更方便。此后,当我们需要调用GameController中的方法时,只需要调用他的单例即可

GameController.GetInstance().MethodName();

4. 总结

在我学习OOP中常用的设计模式的过程中,我的教授表达了并不推荐学生使用单例设计的看法。他认为单例设计 “破例的使用了全局变量,破坏了模块化设计的思想 ”。但此后,我在学习过程中多次看到其他教授使用单例设计,Github上也有一些不小的项目用到过单例设计;同时,我自己在游戏开发过程中也常常感受到这种设计模式带来的便利。所以,我觉得只要合理运用,单例设计也不失为一种好的设计模式。如有不同意见或者高手有什么指教,欢迎评论。

算法、数据结构、与设计模式等在游戏开发中的运用 (一):单例设计(Singleton Design)的更多相关文章

  1. JAVA设计模式:单例设计

    1.单例设计Singleton的引出 单例设计,从名字上首先可以看出单---即只有一个,例---只的是实例化对象:那么单例也就是说一个类,只产生了一个实例化对象.但是我们都知道,一个类要产生实例化对象 ...

  2. [Unity游戏开发]向量在游戏开发中的应用(三)

    本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51088236 在上一篇博客中讲了利用向量点乘在游戏开发中应用的几种情景.本 ...

  3. 【Cocos2d-X游戏实战开发】捕鱼达人之单例对象的设计(二)

    本系列学习教程使用的是cocos2d-x-2.1.4(最新版为cocos2d-x-2.1.5)    博主发现前两个系列的学习教程被严重抄袭,在这里呼吁大家请尊重开发者的劳动成果, 转载的时候请务必注 ...

  4. 借助AMD来解决HTML5游戏开发中的痛点

    借助AMD来解决HTML5游戏开发中的痛点 游戏开发的痛点 现在,基于国内流行引擎(LayaAir和Egret)和TypeScript的HTML5游戏开发有诸多痛点: 未采用TypeScript编译器 ...

  5. [Unity游戏开发]向量在游戏开发中的应用(二)

    本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/50972976 在上一篇博客中讲了利用向量方向的性质来解决问题.这篇博客将继 ...

  6. [Unity游戏开发]向量在游戏开发中的应用(一)

    本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/50810102 向量在游戏开发中是非常实用的,我们在学校学完向量的知识后,只 ...

  7. Cocos2d-x游戏开发中的消息机制:CCNotificationCenter的使用

    在HTML5游戏开发中,js可以使用Event对象的addEventListener(添加事件监听).dispatchEvent(触发事件)实现监听机制,如果在coocos2d-x中,去实现这种机制该 ...

  8. 二、Cocos2dx概念介绍(游戏开发中不同的坐标系,cocos2dx锚点)

    注:ccp是cocos2dx中的一个宏定义,#define ccp(__X__,__Y__)CCPointMake((float)__X__, (float)__Y__),在此文章中表示坐标信息 1. ...

  9. [C++基金会]位计算 游戏开发中的应用

    定义的位操作:通俗点说,,位计算是计算机操作二进制整数. 无论整数可以用二的方式来表示进度,不同类型的其长度的整数位的是不一样的.INT8要么char靠8个月2 位表示,INT16或者short是由1 ...

随机推荐

  1. 力扣832. 翻转图像-C语言实现-简单题

    题目 传送门 文本 给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果. 水平翻转图片就是将图片的每一行都进行翻转,即逆序.例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, ...

  2. ElasticSearcher的安装以及安装过程中出现的问题

    先给出参考链接,带安装成功后再进行总结整个过程. 参考链接:https://blog.csdn.net/fjyab/article/details/81101284 java操作ElasticSear ...

  3. ERROR 1040 (HY000) Too many connections

    C:\Users\Jilil>mysql -u root -pEnter password: *************ERROR 1040 (HY000): Too many connecti ...

  4. 由endl对printf和cout的思考

    [前言]二者的区别就不介绍了.二者使用方法: printf("%s",a); cout<<a<<endl; endl的作用是什么? 一.endl作用 众所周 ...

  5. Codeblocks支持语法着色

  6. 【知识点】 gcc和g++的联系和区别

    目前(2020-09)GCC 编译器已经更新至 10.2版本,其功能也由最初仅能编译 C 语言,扩增至可以编译多种编程语言,其中就包括 C++ . 除此之外,当下的 GCC 编译器还支持编译 Go.O ...

  7. [00]数字图像处理-matlab速成

    原本听的是mooc武汉大学的数字图像处理课程,但是无奈老师读ppt的能力太强,不太适应,后面的课程对于实验方面的要求甚低,无奈之下到处找课程,终于找到了一个适合自己的教程<王伟强-数字图像处理& ...

  8. Microsoft Teams 最新功能发布:协作篇

    正在进行的2021年的Microsoft Ignite大会,发布了一系列跟Microsoft Teams相关的新功能,英文介绍请参考 https://techcommunity.microsoft.c ...

  9. div中如何让文本元素、img元素水平居中且垂直居中

    一.文本元素在div中的水平居中且垂直居中方法 html代码 <div id="box"> <p>文本元素</p> </div> c ...

  10. Go Module实战:基于私有化仓库的GO模块使用实践

    新年开工近一月,2021 年第一期 Open Talk 定档 3 月 18 日晚 8 点,本期我们邀请到了又拍云资深后端开发工程师刘云鹏和我们一起聊聊 Go 最新特性 Go Module 实战. 刘云 ...