【设计模式】CSharp实现创建型模式之-单例模式
本文最后更新于104 天前,其中的信息可能已经过时,如有错误请发送邮件到2289035571@QQ.COM

感谢 TurboAI对本博客的的大力赞助。 创作不易,如果您觉得有帮助,请 支持LIncol29! 为了让我能够继续创作更好的内容,你也可以选择订阅博客的 VIP ,包年VIP仅需10元/年,所有VIP内容免费观看

前言

单例模式是常用的设计模式之一,单例模式只允许被其自身实例化一次,且向外部提供了一个访问该实例的属性。通常来说,单例对象进行实例化时一般不带参数,因为如果不同的实例化请求传递的参数不同的话会导致问题的产生。(若多个请求都是传递的同样的参数的话,工厂模式更应该被考虑)

C#中实现单例有很多种方法,本文将按顺序介绍懒汉式、饿汉式、Lazy< T > 三种方法

单例模式:保证进程中,类型只有一个实例

  • 构造函数私有化,防止他人实例化
  • 提供一个公开、静态的获取实例的方法
  • 返回共用一个静态字段
  • 类前面加sealed 密封类

加 sealed 关键字

防止继承。在单例模式中,我们希望确保这个类只有一个实例,而且不能被继承

提高性能:sealed 类可以被编译器进行某些优化,因为它知道这个类不会被继承。

明确设计意图:告诉其他开发者,这个类不应该被继承。

单例模式写法

一、懒汉式

什么是懒汉式?懒 代表 只有在第一次使用的时候才会加载,如果不使用那么就不会去加载了

  • 双IF语句判断加锁
//懒汉式 sealed关键字
public sealed class Singleton_lazy
{
    //创建私有静态实例
    private  static Singleton_lazy instance;
    //私有锁
    private static readonly object _lock = new object();

   private Singleton_lazy() { }

    //创建静态的、公开的构造实例方法
    public static Singleton_lazy Getinstance()
    {
        if(instance == null)
        {
            lock (_lock)
            {
                if(instance == null)
                {
                    instance = new Singleton_lazy();
                }
            }
        }
        return instance;
    }

    static void Main()
    {
        var instance1 = Singleton_lazy.Getinstance();
        var instance2 = Singleton_lazy.Getinstance();

        //比较两个对象是否相同
        Console.WriteLine(ReferenceEquals(instance1, instance2)); //输出 True
        Console.ReadKey();
    }
}

特点:

  • 只有在首次访问时才创建实例
  • 使用双重检查锁定(double-check locking)来确保线程安全
  • volatile 关键字的作用

  • 内存可见性:多运用在多线程环境中,当一个字段被声明为 volatile,它确保所有线程在访问该字段时都会直接从主内存读取最新的值,而不是从本地缓存中读取。这意味着一个线程对 volatile 字段的修改对其他线程是立即可见的。

  • readonly关键字的作用

  • 确保字段不可变。保证字段的值在对象创建后不可修改:一旦字段被赋值(在构造函数中),它的值就不能被改变。这对于确保数据一致性和保护对象的状态非常有用。

  • 创建不可变类型:使用 readonly 字段可以帮助实现不可变对象。这些对象在创建后无法更改,因此是线程安全的,适合在多线程环境中使用。

二、饿汉式

  • (推荐)静态字段:由CLR保证,在第一次使用这个类型之前,自动初始化并且只初始化一次
//饿汉式 使用静态字段
public sealed class Singleton_hungry
{
    private Singleton_hungry() { }

    private static readonly Singleton_hungry _singleton_hungry = new Singleton_hungry();

    public static Singleton_hungry GetInstance
    {
        get { return _singleton_hungry; }
    }

    static void Main()
    {
        var instance1 = Singleton_hungry.GetInstance;
        var instance2 = Singleton_hungry.GetInstance;

        //比较两个对象是否相同
        Console.WriteLine(ReferenceEquals(instance1, instance2)); //输出 True
        Console.ReadKey();
    }
}
  • 静态构造函数:由CLR保证,在第一次使用这个类型之前,自动被调用且只调用一次
static SingletonPatternSecond()
{
    _singletonPatternSecond = new SingletonPatternSecond();
}

三、Lazy< T > (推荐使用)

此内容查看价格为2.9lincol代币(包年VIP免费),请先
此隐藏内容仅限包年VIP免费查看。包年VIP仅10元,建议升级。VIP可享有哪些特权?

三种方式总结

  • 如果单例的创建和初始化非常耗资源,并且不是每次都需要使用,那么懒汉式更合适。
  • 如果单例的创建和初始化不耗费太多资源,并且每次运行时都会用到,那么饿汉式可能更简单直接。
  • 在现代 .NET 开发中,使用 Lazy 的方式通常是最推荐的,因为它既保证了懒加载,又保证了线程安全,而且实现简单。

单例有什么用?用在哪个场景

同一个实例,不能解决多线程并发问题!会有线程冲突,覆盖数据

单例就是程序只需要这个对象实例化一次

实际应用场景:

  • 唯一序列号
  • 数据库连接池:数据库连接—非托管资源—申请/释放消耗性能。池化资源—内置10个连接—使用来拿,用完放回去避免重复申请和销毁—控制连接数量
  • 线程池
  • 流水号生成器
  • 配置文件读取
  • IOC容器实例

文章参考资料

创作不易,如果您觉得有帮助,请支持LIncol29!
如有需要,请至网站地图学习本博客的教程
博客订阅:通过RSS或关注公众号[Lincol的编程世界] | 广告招租与合作请留言
本文链接:https://www.lincol29.cn/singletonpattern
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0协议转载请注明文章地址及作者哦~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇