1、面向对象语言的23种设计模式-单例模式

一、什么是单例模式

单例模式就是保证进程中,某一个类型只有一个实例。

如图:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZWK6ISR6KKLX1lB,size_20,color_FFFFFF,t_70,g_se,x_16

此时Student被构造了5次,单例模式就是要实现Student只被构造一次。

 

二、单例模式的作用

单例就是对象的重用,例如连接数据库的时候,就不用多次连接,只需要连接一次,防止程序乱连接导致数据库连接池爆满,而且当连接和释放数据库连接时非常耗时,大概就这么个意思。

三、单例模式的使用场景

当使用的类要求只能在程序中出现一次时就需要使用单例模式。

例如:数据库连接池,线程池,流水号生成等等。。

四、如何实现单例模式

首先需要将类的构造函数私有化(使用private关键字),防止其他人随意调用类的构造函数,然后创建一个新的方法,并将此方法暴露出去供其他人使用。

第一种写法(双if加锁):

public class Student
{
    private Student()
    {
        Console.WriteLine("Student被构造了");
    }
    
    private static Student _Student = null;
        public static Student NewClass()
        {
            if (_Student == null)
            {
                _Student = new Student();
            }
            return _Student;
        }
}

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZWK6ISR6KKLX1lB,size_20,color_FFFFFF,t_70,g_se,x_16

此时在主线程中实现了单例,但是还是会有问题,就是多个线程同时调用时还是会被多次实例化,请看下图:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZWK6ISR6KKLX1lB,size_20,color_FFFFFF,t_70,g_se,x_16

在多线程运行时,就会被多次实例化,这是不符合需求的,需要进一步修改。

    public class Student
    {
        private Student()
        {
            Console.WriteLine("Student被构造了");
        }

        private static Student _Student = null;
        private static readonly object lockStudent = new object();
        public static Student NewClass()
        {
            if (_Student == null)
            {
                lock (lockStudent)
                {
                    if (_Student == null)
                    {
                        _Student = new Student();
                    }
                }
            }
            return _Student;
        }
    }

 这是经典的双if判断,请看下图执行结果:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZWK6ISR6KKLX1lB,size_20,color_FFFFFF,t_70,g_se,x_16

这里使用了双if加锁的方式实现了类的单例,当第一个线程进来的时候,是可以通过这三层并且实例化类的,其他线程就会在外面等待,当实例化完成之后在第一个if就会跳出,不会进入到锁等待的阶段,这样就减少了性能消耗。

到此就实现了单例,这是第一种写法。

第二种写法(静态构造函数):

    public class Student
    {
        private Student()
        {
            Console.WriteLine("Student被构造了");
        }

        static Student()
        {
            _Student = new Student();
        }

        private static Student _Student = null;
        public static Student NewClass()
        {
            return _Student;
        }
    }

静态构造函数在程序中任何时候第一次使用此类之前自动调用一次,不会重复调用。

以下为执行结果: 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZWK6ISR6KKLX1lB,size_20,color_FFFFFF,t_70,g_se,x_16

到此就实现了单例,这是第二种写法。

第三种写法(静态字段):

    public class Student
    {
        private Student()
        {
            Console.WriteLine("Student被构造了");
        }

        private static Student _Student = new Student();
        public static Student NewClass()
        {
            return _Student;
        }
    }

 这个与上一个方法差不多,以下为执行结果:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZWK6ISR6KKLX1lB,size_20,color_FFFFFF,t_70,g_se,x_16

五、单例模式的优缺点

单例模式并不能防止线程冲突。

实现了单例模式的类可以在全局中保持唯一,可以随时使用,看下图:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZWK6ISR6KKLX1lB,size_20,color_FFFFFF,t_70,g_se,x_16

如果此类不是单例,哪么这个地方应该是1,因为类被重新实例化哪么num就会被重新赋值,当类是单例模式时,就不会出现这种情况,哪么不管在哪里调用这个num都会输出被处理后的值。

大概就这么个意思。

完。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啊脑袋_YA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值