• 单例模式再议


    1.前言

    曾多次对unity或者c#在使用单例时的一些问题进行过讨论,即有充满戾气的讨论,也有理性的总结封装(封装成一个抽象类,使用时直接继承),但多次使用时还是有一些不同的想法,故此文章诞生。此文将从纯C# 层展开。

    2.单例的几种方式

    此部分为纯C#层面

    2.1 非线程安全模式

    此种线程不安全,即多个线程同时初次调用单例时会产生空引用问题。

    public sealed class Singleton
    {
        private static Singleton instance = null;
    
        private Singleton(){}
    
        public static Singleton instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }
    
    

    2.2 简单线程安全模式

    此方式通过锁实现线程安全,简单有效,但是由于获取单例时每次都需要走锁,会有一定的性能问题(普通应用下可以忽略不记)。

    public sealed class Singleton
    {
        private static Singleton instance = null;
        private static readonly object padlock = new object();
    
        Singleton(){}
    
        public static Singleton Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                    return instance;
                }
            }
        }
    }
    关于锁的问题可以参考:https://www.cnblogs.com/wolf-sun/p/4209521.html
    

    2.3 双重验证线程安全模式

    此种方式实在上一种方式中在过锁前加了一个判断,来避免多次过锁。

    public sealed calss Singleton
    {
        private static Singleton instance = null;
        private static readonly object padlock = new object();
    
        Singleton()
        {
        }
    
        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (padlock)
                    {
                        if (instance == null)
                        {
                            instance = new Singleton();
                        }
                    }
                }
                return instance;
            }
        } 
    }
    
    

    2.4 非锁模式的线程安全

    即利用C# 静态方法或变量的特性,实现线程安全,即保证所有的线程在调用时,单例已经生成,不需要判断单例为空。此方案在unity中曾多次使用,如此文描述,但也会存在一些问题。

    public sealed class Singleton
    {
        //在Singleton第一次被调用时会执行instance的初始化
        private static readonly Singleton instance = new Singleton();
    
        //Explicit static consturctor to tell C# compiler 
        //not to mark type as beforefieldinit
        static Singleton()
        {
        }
    
        private Singleton()
        {
        }
    
        public static Singleton Instance
        {
            get
            {
                return instance;
            }
        }
    }
    
    

    2.5 其他模式

    还有一些其他模式如完全延时加载以及Lazy等,再次不再赘述。

    3.Unity单例模式

    3.1 特殊性

    在unity中使用单例时,有如下三个特殊性:
    1)线程安全性。由于涉及渲染对象操作都是在主线程中,所以除数据类问题、或者纯C#层问题外,基本都是单线程,所以在很大程度上不用考虑单例的线程安全性。
    2)脚本的挂载操作。由于unity中使用类时并非直接使用或者new出一个对象,所以即使使用单例也会存在不同游戏物体上会挂载多个单例类(手误操作或者多人协作等导致)。
    3)初始化问题。数据初始化一般都在MonoBehaviour的Awake或者Start中进行,这导致一些问题不同于C#原生单例。

    3.2 一个单例

    回归到本质,在unity中要防止为了使用单例而使用,要做好前期规划,由于种种问题,很难做到两全,所以做好预防处理即可。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class XXXManager : MonoBehaviour
    {
        private static XXXManager instance;
    
        public static XXXManager GetInstance()
        {
            if (instance == null)
            {
                Debug.LogError("Null reference of XXXManager instance");
            }
            return instance;
        }
    
        private void Awake()
        {
            if (instance != null)
            {
                Debug.Log("Multiple instance of XXXManager");
            }
            else
            {
                instance = this;
            }
        }
    }
    
    

    4.结论

    无结论

  • 相关阅读:
    uva 550
    uva 10110
    uva 10014
    uva 10177
    uva 846
    Dear Project Manager, I Hate You
    创业型软件公司的心得
    架构设计的心得
    程序员常去的103个网站
    66个经典源码网站
  • 原文地址:https://www.cnblogs.com/llstart-new0201/p/14773794.html
Copyright © 2020-2023  润新知