开发过程中,单例模式是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。以下是几种常见的单例模式实现方式,包括它们的优缺点和使用示例。

1. 懒汉式单例(Lazy Initialization)

懒汉式单例在第一次被访问时才创建实例,适合于资源消耗较大的对象。

a. 线程不安全的懒汉式单例

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}

优点:
• 延迟初始化,节省资源。
缺点:
• 不是线程安全的,在多线程环境下可能会创建多个实例。

b. 线程安全的懒汉式单例

public class Singleton
{
    private static Singleton instance;
    private static readonly object lockObject = new object();

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (lockObject)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
}

优点:
• 延迟初始化,节省资源。
• 线程安全。
缺点:
• 双重检查锁定(Double-Check Locking)稍微复杂一些。

2. 饿汉式单例(Eager Initialization)

饿汉式单例在类加载时就创建实例,适合于资源消耗较小的对象。

public class Singleton
{
    private static readonly Singleton instance = new Singleton();

    private Singleton() { }

    public static Singleton Instance
    {
        get { return instance; }
    }
}

优点:
• 线程安全。
• 实现简单。
缺点:
• 不能延迟初始化,可能会浪费资源。

3. 静态内部类单例

静态内部类单例在 Java 中常用,但在 C# 中也可以实现类似的模式。

public class Singleton
{
    private Singleton() { }

    private static class SingletonHolder
    {
        internal static readonly Singleton Instance = new Singleton();
    }

    public static Singleton Instance
    {
        get { return SingletonHolder.Instance; }
    }
}

优点:
• 线程安全。
• 延迟初始化。
缺点:
• 实现稍微复杂一些。

4. 使用 Lazy 实现单例

Lazy 提供了一种线程安全且延迟初始化的方式。

public class Singleton
{
    private static readonly Lazy<Singleton> lazyInstance = new Lazy<Singleton>(() => new Singleton());

    private Singleton() { }

    public static Singleton Instance
    {
        get { return lazyInstance.Value; }
    }
}

优点:
• 线程安全。
• 延迟初始化。
• 实现简单。
缺点:
• 需要 .NET Framework 4.0 及以上版本。

5. 使用属性初始化器实现单例

从 C# 6.0 开始,可以使用属性初始化器简化单例的实现。

public class Singleton
{
    private static Singleton instance = new Singleton();

    private Singleton() { }

    public static Singleton Instance => instance;
}

优点:
• 线程安全。
• 实现简单。
缺点:
• 不能延迟初始化。

6. 使用静态构造函数实现单例

静态构造函数在类第一次被访问时自动调用,确保线程安全。

public class Singleton
{
    static Singleton()
    {
        instance = new Singleton();
    }

    private static Singleton instance;

    private Singleton() { }

    public static Singleton Instance
    {
        get { return instance; }
    }
}

优点:
• 线程安全。
• 实现简单。
缺点:
• 不能延迟初始化。

7. 优缺点总结

实现方式 优点 缺点
懒汉式(线程不安全) 延迟初始化,节省资源 不是线程安全的
懒汉式(线程安全) 延迟初始化,线程安全 实现稍微复杂一些
饿汉式 线程安全 实现简单 不能延迟初始化 可能会浪费资源
静态内部类 线程安全,延迟初始化 实现稍微复杂一些
Lazy 线程安全,延迟初始化,实现简单 需要 .NET Framework 4.0 及以上版本
属性初始化器 线程安全,实现简单 不能延迟初始化
静态构造函数 线程安全,实现简单 不能延迟初始化

所谓的,延迟初始化 的主要目的是在对象真正需要时才创建它,从而节省资源;

8. 使用示例

using System;

class Program
{
    static void Main()
    {
        Singleton instance1 = Singleton.Instance;
        Singleton instance2 = Singleton.Instance;

        Console.WriteLine(instance1 == instance2); // 输出 True,表示两个实例是同一个对象
    }
}

9. 总结

选择哪种单例模式取决于具体的需求和环境。如果你需要延迟初始化并且确保线程安全,推荐使用 Lazy 或者线程安全的懒汉式单例。如果你不需要延迟初始化,可以选择饿汉式或静态构造函数实现。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐