创建型模式-单例模式(一)

目录

单例模式描述

单线程应用

多线程应用


单例模式描述

单例模式,Singleton,是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

单例模式存在的问题:

1.保证一个类只有一个实例。意思就是一个程序里面,只有一个实例,可以创建多次,最终只有一个实例。最常见是控制某些共享资源 (例如数据库,文件,或者日志) 的访问权限。它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的对象, 而不是一个新对象。

2.为该实例提供一个全局访问节点。 还记得你 用过的那些存储重要对象的全局变量吗? 它们在使用上十分方便, 但同时也非常不安全, 因为任何代码都有可能覆盖掉那些变量的内容, 从而引发程序崩溃。和全局变量一样, 单例模式也允许在程序的任何地方访问特定对象。 但是它可以保护该实例不被其他代码覆盖。还有一点: 你不会希望解决同一个问题的代码分散在程序各处的。 因此更好的方式是将其放在同一个类中, 特别是当其他代码已经依赖这个类时更应该如此。

解决方案:

  • 将默认构造函数设为私有, 防止其他对象使用单例类的 new运算符。
  • 新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。

使用场景:

1.如果程序中的某个类对于所有客户端只有一个可用的实例, 可以使用单例模式。

2.如果你需要更加严格地控制全局变量, 可以使用单例模式。

优缺点对比:

优点缺点
你可以保证一个类只有一个实例违反了单一职责原则。 该模式同时解决了两个问题
你获得了一个指向该实例的全局访问节点单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等
仅在首次请求单例对象时对其进行初始化该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象
单例的客户端代码单元测试可能会比较困难, 因为许多测试框架以基于继承的方式创建模拟对象。 由于单例类的构造函数是私有的, 而且绝大部分语言无法重写静态方法, 所以你需要想出仔细考虑模拟单例的方法。 要么干脆不编写测试代码, 或者不使用单例模式

除此之外还听说,饿汉模式,懒汉模式(也叫做懒惰模式)。

饿汉式,表示自己一直很饿,主动去劳动,一开始类加载的时候就已经实例化了,并且创建单例对象,以后只管用。

懒汉式,表示自己很懒,不想动弹,一开始不会实例化,什么时候用就什么时候new,才进行实例化。

所以,此处就可以根据你自己的程序,启动的时候耗资源和时间的实际情况选择。 

单线程应用

1.建立单例Singleton类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    //public,公开的,用于外面的类使用时调用 
    public class Singleton
    {
        private static Singleton instance; //声明一个静态类字段,用于存储
        private Singleton() //private,私有的,防止使用new直接构造
        {
            MyProperty = someBusinessLogic(1, 2);
        }
        public static Singleton GetInstance() //public,公开的,用于外面的类,直接调用
        {
            if (instance == null)     //第一次为null会进来, 第二次就不为null,直接返回
            {
                instance = new Singleton(); //第一次赋值于_instance
            }
            return instance;
        }
        public void someBusinessLogic()   //建立其他业务逻辑方法,可以在单例中运行,无参数,无返回值
        {
            Console.WriteLine("常用方法");
        }
        public int someBusinessLogic(int a, int b)   //建立其他业务逻辑方法,可以在单例中运行,有参数,有返回值
        {
            someBusinessLogic();
            return a + b;
        }

        public int MyProperty { get;  }
    }
}

2.应用

using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            //Singleton s1 = Singleton.GetInstance();

            //Singleton s2 = Singleton.GetInstance();

            //if (s1 == s2)
            //{
            //    Console.WriteLine("相同");
            //    s1.someBusinessLogic();
            //    int c = s1.someBusinessLogic(1, 2);
            //    Console.WriteLine(c);

            //    s2.someBusinessLogic();
            //    int c2 = s2.someBusinessLogic(2, 2);
            //    Console.WriteLine(c2);
            //}
            //else
            //{
            //    Console.WriteLine("不相同");
            //}

            for (int i = 0; i < 5; i++)
            {
              int a=  Singleton.GetInstance().MyProperty;
                Console.WriteLine(  a);
            }
        }
    }
}

3.结果

可见调用5次,实例只有一个 。

多线程应用

1.建立单例Singleton类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    //public,公开的,用于外面的类使用时调用
    public class Singleton
    {
        private static Singleton instance; //声明一个静态类字段,用于存储
        public string TestValue { get;  } //用于运行的时候测试是否是同一个单例,真实情况不需要写

        private static volatile object _lock = new object(); //readonly,定义和构造的时候可以赋值,其他地方不能赋值
        private Singleton(string a) //private,私有的,防止使用new直接构造
        {
            TestValue = someBusinessLogic(a);
        }

        public static Singleton GetInstance(string value) //public,公开的,用于外面的类,直接调用
        {
            if (instance == null)     //第一次为null会进来, 第二次就不为null,直接返回
            {
                lock (_lock) //多线程会进来,如果有值,先锁住
                {
                    if (instance == null)   //第一次为null会进来
                    {
                        instance = new Singleton(value);
                        //instance.testValue = value;       //测试值
                    }
                }
            }
            return instance;
        }
        public string someBusinessLogic(string a)   //建立其他业务逻辑方法,可以在单例中运行,无参数,无返回值
        {
            Console.WriteLine("常用方法");
            return a;
        }
        public int someBusinessLogic(int a, int b)   //建立其他业务逻辑方法,可以在单例中运行,有参数,有返回值
        {
            return a + b;
        }
    }
}

还可以使用get的方式写,不能传值,此种方式是可以传值的。 

2.应用

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Run(() => TestSingleton("1"));  //第一个线程
            Task.Run(() => TestSingleton("2"));  //第二个线程

            Console.WriteLine("结束");
        }

        public static void TestSingleton(string value)
        {
            Singleton singleton = Singleton.GetInstance(value);
            singleton.someBusinessLogic(1,2);
            int c = singleton.someBusinessLogic(1, 2);
            Console.WriteLine(c);
            Console.WriteLine(singleton.TestValue);
        }
    }
}

3.结果

这个结果有时候1,有时候2。恰恰就说明了,如果第一个线程先执行了,就创建的是1,如果第二个线程先执行,就创建的是2。也可以直接读取TestValue的值,那么someBusinessLogic方法就只执行了一次。

多线程中,还可以使用Lazy<T>的当方式去写。

using ConsoleApp1;
using System;
using System.IO;
using System.Net.Sockets;

class Program
{
    static void Main(string[] args)
    {
        string a = Singleton.Instance.A;
    }
}

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

    private string a;
    public string A
    {
        get { return a; }
    }
    private Singleton()
    {
        a = GetA();
    }
    private string GetA()
    {
      return Guid.NewGuid().ToString();
    }
}

来源:创建型模式-单例模式(一)_单例模是一种创建型模式_故里2130的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

故里2130

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

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

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

打赏作者

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

抵扣说明:

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

余额充值