设计模式-单例模式

 单例模式(Singleton)是一种常用的设计模式,它保证一个类只有一个实例,并提供一个全局访问点。

单例模式的主要特征是:

  • - 构造函数是私有的,外部不能直接创建对象,只能通过类提供的静态方法获取实例。
  • - 类中提供一个静态方法,用于获取其唯一实例。
  • - 类中提供一个静态变量,用来保存该类唯一的实例。
  • - 类声明为 sealed,防止被继承。

单例模式的优点:

  • - 在内存中只有一个实例,减少了内存开销。
  • - 避免对资源的多重占用。
  • - 设置全局访问点,严格控制访问。

单例模式的缺点:

  • - 没有接口,不能继承,与单一职责原则相违背。
  • - 扩展困难。- 如果实例化的过程比较复杂,会给系统带来性能开销。
  • - 如果实现不当,可能导致线程不安全。- 测试不易。

一、C#中的单例模式

 1.单线程单例模式

public class Singleton
    {
        private static Singleton instance;//私有静态变量
        private Singleton() { }
        public static Singleton Instance()
        {
            if (instance == null)
                instance = new Singleton();
            return instance;
        }
    }

2.简单线程安全

    

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

    

 

        变化不大,基于前面的分析,这个只是添加了一个object成员以此来实现锁。这种方法是线程安全的,每个线程要创建实例时,都要先去得锁,然后再判断是否为空,也就是保证多线程运行时,只有一个线程能进行进行实例化,而一旦一个线程实例化后,后面的线程取到锁后,就会发现实例已经创建。但是这个方法也有一个明显的缺点:假设线程足够多,100个吧,每一个线程在进行if(instance==null)判断时,都到等到某一个线程退出后将锁获得。所以会导致性能问题。改进的办法就是多进行以此判断,如果instance==null是FALSE,那自然没必要在等待锁,再去判断一次。

3.双层验证下的多线程安全

        

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

4.更高效的单例模式——饿汉模式

        这种方式主要利用了C#的“静态初始化方法”,这种方法不需要你显示的编写线程安全的代码,就可以保证线程安全。

 public sealed class Singleton3
        {
            private static readonly Singleton3 instance = new Singleton3();
 
            static Singleton3() { }
            private Singleton3() { }
 
            public static Singleton3 Instance
            {
                get
                {
                    return instance;
                }
            }
 
 
        }

        正如你看到的,这个似乎比前面两种实现都要简单,它是如何保证线程安全的呢?对于每个AppDomain,在C#中类的实例被构造或者静态成员被引用时,静态构造函数才会执行,而且只执行一次。由于这个类在一加载就被实例化,因此,效率上要比前面实现高的多。

        那为何叫饿汉模式呢?这是因为相对于第2、3的实现方式,Singleton必选被引用一次后才会将自己实例化,这种成为懒汉式;而当下,无论我们在程序中用不用,编译器都会实例化一个对象,所以就成为“饿汉模式”

        那我们看另外一种懒汉模式:

5. 懒汉模式——利用嵌套类

        


public sealed class Singleton
{
    private Singleton()
    {
    }
 
    public static Singleton Instance { get { return Nested.instance; } }
 
    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }
 
        internal static readonly Singleton instance = new Singleton();
    }
}
 

当嵌套类的静态成员第一次被引用到时,就会触发实例化,因此这是一种懒汉式单例模式。但是有着前面所有模式的有点,因此相当推荐!请注意,尽管嵌套类可以访问封闭类的私有成员,但情况并非如此,因此这里实例需要是内部的。不过,这不会引起任何其他问题,因为类本身是私有的。然而,为了使实例化变得懒惰,代码要复杂一些。

6. 使用net4之后的Lazy泛型

        在.net4之后,可以使用System.Lazy<T>类型实现迟实例化,你唯一需要做的就是传递一个代理便令给单例类的构造函数,可以用lambda表达式轻松实现:


public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());
 
    public static Singleton Instance { get { return lazy.Value; } }
 
    private Singleton()
    {
    }
}

        上面的代码会隐式的调用LazyThreadSafetyMode.ExecutionAndPublication以实现lazy<Singleton>线程安全模式.

二、Unity中的单例模式

1.Unirt中的泛型单例模式

public class Singleton<T> where T : new()
{
    private static T _instance;
    public static T GetIstance()
    {
        if (_instance == null)
            _instance = new T();
        return _instance;
    }
}

2.Unity中继承MonoBehaviour的单例模式

//继承了MonoBehaviour的 单例模式 需保证其唯一性,不能拖拽多个到脚本上
public class SingeletonMono<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    public static T GetInstance()
    {
        return instance;
    }

    //防止被子类改写   子类若想在Awake中写逻辑,需重写并保留Base
    protected virtual void Awake()
    {
        instance = this as T;
    }
}

3.Unity中继承MonoBehaviour的自动单例模式

//继承自动创建的单例模式基类,不需要手动拖拽,只需直接GetInsatance
public class SingeletonAutoMono<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    public static T GetInstance()
    {
        if (instance == null)
        {
            GameObject obj = new GameObject();
            //设置对象的名字为脚本名
            obj.name = typeof(T).ToString();
            //让次单例模式对象 切换场景时  不移除     单例模式对象 往往是成个程序生命周期中的
            DontDestroyOnLoad(obj);
            instance = obj.AddComponent<T>();
        }
        return instance;
    }
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值