C# 单例模式学习

在C#中,单例模式(Singleton Pattern)是一种常用的设计模式,用于确保一个类只有一个实例,并提供全局访问点。单例模式主要有三种实现方式:饿汉式、懒汉式和双重检查锁定。下面分别介绍这三种方式的实现。

1. 饿汉式(Eager Initialization)

饿汉式是在类加载时就初始化单例实例,线程安全,但如果单例类实例占用资源较多且未被使用,会造成资源浪费。

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

    // 私有构造函数,防止外部实例化
    private Singleton() { }

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

2. 懒汉式(Lazy Initialization)

懒汉式是在需要时才创建实例,非线程安全,如果在多线程环境下使用需要额外处理同步问题。

public sealed class Singleton
{
    private static Singleton instance = null;

    // 私有构造函数,防止外部实例化
    private Singleton() { }

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

3. 双重检查锁定(Double-Checked Locking)

双重检查锁定结合了饿汉式和懒汉式的优点,确保线程安全的同时,减少了不必要的锁开销。

public sealed class Singleton
{
    private static Singleton instance = null;
    private static readonly object lockObj = new object();

    // 私有构造函数,防止外部实例化
    private Singleton() { }

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

4. 静态内部类(Static Inner Class)

这种方法是利用CLR(Common Language Runtime)的初始化类型特性,既实现了延迟加载,又保证了线程安全。

public sealed class Singleton
{
    private Singleton() { }

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

    private class Nested
    {
        static Nested() { }
        internal static readonly Singleton instance = new Singleton();
    }
}

5. 使用.NET 4的Lazy<T>

利用.NET 4引入的Lazy<T>类,可以非常简洁地实现线程安全的单例模式。

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

    private Singleton() { }

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

它的作用和优势可以总结为以下几点:

1. 控制实例数量

单例模式通过限制类的实例化次数,确保整个应用程序中该类只有一个实例。这在以下情况下非常有用:

  • 资源管理:如数据库连接池、线程池等,这些资源需要统一管理,避免资源浪费和竞争。
  • 配置管理:应用程序的配置通常只有一份,全局共享配置可以避免重复加载和不一致的问题。

2. 全局访问点

单例模式提供一个全局访问点,便于在整个应用程序的任何地方访问该实例。例如:

  • 日志记录:日志系统通常需要全局访问,以记录应用程序的运行情况。
  • 缓存:全局缓存实例可以提高性能,减少数据库或其他存储的访问次数。

3. 延迟初始化

某些单例实现方式支持延迟初始化(如懒汉式和双重检查锁定),只有在需要时才创建实例,可以提高程序启动速度,节省内存。

4. 线程安全

通过适当的实现方式,单例模式可以保证线程安全,确保在多线程环境下不会创建多个实例。例如使用双重检查锁定或.NET 4的Lazy<T>。

5. 避免重复

单例模式避免了在多个地方创建同一个类的实例,从而减少了对象的重复创建,节省了内存,并简化了对象的管理。

实际应用场景

以下是一些常见的单例模式应用场景:

  • 配置管理类:应用程序的配置信息通常需要全局访问且只有一份。
  • 日志类:日志记录器需要在整个应用程序中共享,避免多次创建。
  • 线程池:线程池的实例需要在应用程序中共享,以有效管理线程资源。
  • 数据库连接池:数据库连接池实例化需要大量资源,因此需要共享一个连接池实例来管理数据库连接。

例如实现一个使用单例模式的日志类,可以确保日志系统在整个应用程序中只有一个实例,并且提供一个全局访问点。以下是一个简单的示例,展示了如何使用C#中的单例模式来实现日志类。

1. 饿汉式单例实现日志类

using System;
using System.IO;

public sealed class Logger
{
    // 饿汉式,在类加载时创建实例
    private static readonly Logger instance = new Logger();

    // 私有构造函数,防止外部实例化
    private Logger() 
    {
        // 这里可以初始化日志文件或其他资源
    }

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

    // 日志记录方法
    public void Log(string message)
    {
        // 简单写入控制台,可以扩展为写入文件或其他日志系统
        Console.WriteLine($"{DateTime.Now}: {message}");
    }
}

2. 懒汉式单例实现日志类(线程不安全)

using System;
using System.IO;

public sealed class Logger
{
    private static Logger instance = null;

    private Logger() 
    {
        // 这里可以初始化日志文件或其他资源
    }

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

    public void Log(string message)
    {
        Console.WriteLine($"{DateTime.Now}: {message}");
    }
}

3. 双重检查锁定单例实现日志类(线程安全)

using System;
using System.IO;

public sealed class Logger
{
    private static Logger instance = null;
    private static readonly object lockObj = new object();

    private Logger() 
    {
        // 这里可以初始化日志文件或其他资源
    }

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

    public void Log(string message)
    {
        Console.WriteLine($"{DateTime.Now}: {message}");
    }
}

4. 使用.NET 4的Lazy<T>单例实现日志类(线程安全)

using System;
using System.IO;

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

    private Logger() 
    {
        // 这里可以初始化日志文件或其他资源
    }

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

    public void Log(string message)
    {
        Console.WriteLine($"{DateTime.Now}: {message}");
    }
}

使用示例

class Program
{
    static void Main(string[] args)
    {
        Logger logger = Logger.Instance;
        logger.Log("This is a log message.");
        
        // 可以在应用程序的任何地方使用Logger.Instance来记录日志
        AnotherClass.DoSomething();
    }
}

public class AnotherClass
{
    public static void DoSomething()
    {
        Logger logger = Logger.Instance;
        logger.Log("Doing something in another class.");
    }
}

总结

单例模式通过确保某个类只有一个实例,提供全局访问点,节省资源并保证一致性。它在很多实际应用中非常有用,特别是在需要共享资源或配置的场景中。选择适当的单例实现方式,可以确保线程安全和延迟加载,提高应用程序的性能和可维护性。

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值