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

定义

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

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;
        }
    }

}

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

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>