游戏设计模式----单例模式

Posted _不动明王

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏设计模式----单例模式相关的知识,希望对你有一定的参考价值。

定义

单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。

C#

单例模式主要分两种

饿汉式

在类加载时已经创建好该单例对象。

public class Test_Instan


    private static Test_Instan instant=new Test_Instan();
    public static Test_Instan Instant
    
        get
        
           return instant;
        
       
private Test_Instan()
    

    

懒汉式

在真正需要使用对象时才去创建该单例类对象

public class Test_Instan

    private static Test_Instan instant;
    public static Test_Instan Instant
    
        get
        
            if (instant==null)
            
                instant = new Test_Instan();
            
           return instant;
        
  

private Test_Instan()
    

 


不足之处:如果两个线程同时判断instant为空那么它们都会去实例化一个Test_Instan对象,这就变成双例了。

改进:利用锁

public class Test_Instan
	private Test_Instan()
    

 	
    private static Test_Instan instant;
    private static object syncRoot = new object();
    public static Test_Instan Instant
    
        get
        
            if (instant == null) // 假如线程A和线程B同时看到instant为null
            
                lock (syncRoot)//线程A或者线程B获得该锁进行初始化,另一线程阻塞
                
                    if (instant == null)//其中一个线程进入该分支创建单例对象,另外一个阻塞线程,阻塞结束后进入该分支则会发现instant已被创建
                    
                        instant = new Test_Instan();
                    
                
            
                   
           return instant;
        
      


Unity的单例

饿汉式

类似与我们上面的饿汉式,不过这里要注意的是Awake函数的执行顺序是不可控的,通俗来说每次运行程序的时候每个脚本的执行顺序都不一样,通常我们会自己写一个初始函数函数,来控制我们的执行循序,确保单例的初始化在所有的逻辑之上。

public class SingletonUnity : MonoBehaviour


    private static SingletonUnity instant;
    public static SingletonUnity Instant
    
        get
        
            return instant;
        
    
    private void Awake()
    
        instant = this;
    

懒汉式

由于unity的所有继承自MonoBehaviour的脚本都必须挂在一个游戏对象上,否则无法执行,也谈不上用new来实例化,这点我们要尤为注意。

public class SingletonUnity : MonoBehaviour

    private static SingletonUnity instant;

    public static SingletonUnity Instant
    
        get
        
            if (instant==null)
            
                instant= FindObjectOfType<SingletonUnity>();
                if (instant==null)
                
                    GameObject instan_ = new GameObject();
                    instant = instan_.AddComponent<SingletonUnity>();
                
            
            return instant;
        
    

问题

对比我们上面纯C#的写法,在Unity创建的MonoBehaviour类的单例并没有对MonoBehaviour类的实例化进行非公有化,因为,在Unity中,MonoBehaviour类有可视化操作的特点,当我们手动拖拽多个单例脚本到游戏中,这时我们运行程序很可能会出现逻辑错误,我们单例模式的原则或者说目的是保证一个类只有一个实例,所以我们需要改进一下。

public class SingletonUnity : MonoBehaviour

    private static SingletonUnity instant;

    public static SingletonUnity Instant
    
        get
        
            if (instant == null)
            
                SingletonUnity[] instants = FindObjectsOfType<SingletonUnity>();                 
                  for (int i = 0; i < instants.Length; i++)
                  
                    Destroy(instants[i].gameObject);
                  

                GameObject instan_ = new GameObject();
                instant = instan_.AddComponent<SingletonUnity>();
            
            return instant;
        
    

   

最后写个测试脚本测试下

public class Client_sigle : MonoBehaviour 


    void Start()
    
        Debug.Log(SingletonUnity.Instant.name);
       
    
  


运行前


运行后

当然,你也可以按自己的需求,更改上面写法。

改进:上面单例的写法代码量比较多,当游戏中有多个单例,显然不可能用我们的复制粘贴,这时我们可以用泛型来增强我们的复用性。

public class SingletonUnity<T> : MonoBehaviour where T: MonoBehaviour

    private static T instant;

    public static T Instant
    
        get
        
            if (instant == null)
            
                T[] instants = FindObjectsOfType<T>();                 
                  for (int i = 0; i < instants.Length; i++)
                  
                    Destroy(instants[i].gameObject);
                  

                GameObject instan_ = new GameObject();
                instant = instan_.AddComponent<T>();
            
            return instant;
        
    


只需要让单例继承该类即可。

以上是关于游戏设计模式----单例模式的主要内容,如果未能解决你的问题,请参考以下文章

[Unity设计模式与游戏开发]单例模式

[Unity设计模式与游戏开发]单例模式

游戏编程模式--单例模式

Cocos Creator游戏开发中单例的实现

Unity游戏基本框架

一个游戏所用到的设计模式