单例模式(Singleton Pattern)

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/397 访问。

单例模式属于创建型模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。

一个类有且仅有一个实例,并且自行实例化向整个系统提供。

角色:

1、单例类(Singleton)

保证唯一并提供全局访问点的单例类。

命名空间SingletonPattern中包含7个单例类,本案例将介绍这7种常见的单例实现方法。

namespace SingletonPattern
public sealed class Singleton {private static Singleton _instance = null;public static Singleton GetInstance() {if(_instance == null) {_instance = new Singleton();Console.WriteLine("Singleton.GetInstance()!");}return _instance;}}

最常见的单例类,但是无法保证线程安全。因为首次运行时,n个线程可同时到达if(_instance == null),导致_instance可能会被多初始化n-1次(有1次是需要初始化的)。在_instance被初始化之后新启动的线程不会使该情况重现。

public sealed class SingletonSafe {private static SingletonSafe _instance = null;private static readonly object _lock = new object();public static SingletonSafe GetInstance() {lock (_lock) {if (_instance == null) {_instance = new SingletonSafe();Console.WriteLine("SingletonSafe.GetInstance()!");}}return _instance;}}

使用私有静态object类型的锁(微软推荐),lock关键字会占有该锁,之后请求该锁的其它线程必需等待其释放才能进入。该方法可实现线程安全的单例模式,但是锁属于昂贵资源,“占有锁”和“释放锁”都比较耗时,并会在一定程度上阻止其它线程的执行,会显著影响程序的并发性,所以有了下面的优化。

public sealed class SingletonSafe2 {private static SingletonSafe2 _instance = null;private static readonly object _lock = new object();public static SingletonSafe2 GetInstance() {if (_instance == null) {lock (_lock) {if (_instance == null) {_instance = new SingletonSafe2();Console.WriteLine("SingletonSafe2.GetInstance()!");}}}return _instance;}}

通过优先使用if (_instance == null)这种耗费资源较少的比较来决定是否进入锁,可大幅度提高性能。因为_instance不为null时,直接返回即可。

public sealed class SingletonLazy {private static readonly Lazy<SingletonLazy> _instance =new Lazy<SingletonLazy>(() => {Console.WriteLine("SingletonLazy.GetInstance()!");return new SingletonLazy();});public static SingletonLazy GetInstance() {return _instance.Value;}}

带泛型的Lazy式单例实现,这是线程安全的,仅提供给大家参考。

public sealed class SingletonReadOnly {private static readonly SingletonReadOnly _instance =new SingletonReadOnly();public SingletonReadOnly() {Console.WriteLine("SingletonReadOnly.GetInstance()!");}public static SingletonReadOnly GetInstance() {return _instance;}}

静态只读式单例实现(由运行时保证唯一),这是线程安全的,仅提供给大家参考。

public abstract class SingletonGenericBase<T> where T : class, new() {private static T _instance = null;private static readonly object _lock = new object();public static T GetInstance() {if (_instance == null) {lock (_lock) {if (_instance == null) {_instance = new T();Console.WriteLine("SingletonGeneric.GetInstance()!");}}}return _instance;}}public sealed class SingletonGeneric : SingletonGenericBase<Singleton> {public SingletonGeneric() { }}

复杂的泛型实现,这是线程安全的,仅提供给大家参考。

public abstract class SingletonGenericBase2<T> where T : class {private static readonly Lazy<T> _instance = new Lazy<T>(() => {var ctors = typeof(T).GetConstructors(BindingFlags.Instance| BindingFlags.NonPublic| BindingFlags.Public);if (ctors.Count() != 1)throw new InvalidOperationException(String.Format("Type {0} must have exactly one constructor.",typeof(T)));var ctor = ctors.SingleOrDefault(c => !c.GetParameters().Any() && c.IsPrivate);if (ctor == null)throw new InvalidOperationException(String.Format("The constructor for {0} must be private and take no parameters.",typeof(T)));Console.WriteLine("SingletonGeneric2.GetInstance()!");return (T)ctor.Invoke(null);});public static T GetInstance() {return _instance.Value;}}public sealed class SingletonGeneric2 : SingletonGenericBase2<SingletonGeneric2> {private SingletonGeneric2() { }}

复杂的泛型实现,这是线程安全的,仅提供给大家参考。

public class Program {public static void Main(string[] args) {var singleton = Singleton.GetInstance();singleton = Singleton.GetInstance();var singletonSafe = SingletonSafe.GetInstance();singletonSafe = SingletonSafe.GetInstance();var singletonSafe2 = SingletonSafe2.GetInstance();singletonSafe2 = SingletonSafe2.GetInstance();var singletonReadOnly = SingletonReadOnly.GetInstance();singletonReadOnly = SingletonReadOnly.GetInstance();var singletonLazy = SingletonLazy.GetInstance();singletonLazy = SingletonLazy.GetInstance();var singletonGeneric = SingletonGeneric.GetInstance();singletonGeneric = SingletonGeneric.GetInstance();var singletonGeneric2 = SingletonGeneric2.GetInstance();singletonGeneric2 = SingletonGeneric2.GetInstance();Console.ReadKey();}}

以上是调用方的代码,每个GetInstance方法均调用2次以展示效果。以下是这个案例的输出结果:

Singleton.GetInstance()!
SingletonSafe.GetInstance()!
SingletonSafe2.GetInstance()!
SingletonReadOnly.GetInstance()!
SingletonLazy.GetInstance()!
SingletonGeneric.GetInstance()!
SingletonGeneric2.GetInstance()!

优点:

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/397 访问。

1、单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例;
2、因为类控制了实例化过程,所以类可以灵活更改实例化过程。

缺点:

1、没有接口,不能继承,与单一职责原则冲突。

使用场景:

1、需要频繁的进行创建和销毁的对象;
2、创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
3、工具类对象;
4、频繁访问数据库或文件的对象。

C#设计模式之5-单例模式相关推荐

  1. 设计模式之一:单例模式

    设计模式之一:单例模式 目录介绍 1.单例模式介绍 2.单例模式定义 3.单例模式使用场景 4.单例模式的实现方式 4.1 懒汉式[线程不安全] 4.2 懒汉式[**synchronized 线程安全 ...

  2. golang atomic load 性能_设计模式之Golang单例模式

    今天给大家讲下什么是单例模式,以及在Go语言中如何用正确的姿势实现它.其实单例模式是一种在平时开发中经常用到的软件设计模式.在设计模式结构中,其核心是只包含一个被称为单例的特殊类.通过单例模式可以确保 ...

  3. 单例设计模式 序列化破坏单例模式原理解析及解决方案?

    单例设计模式 序列化破坏单例模式原理解析及解决方案? 序列化和反序列化 反射的破坏

  4. Java设计模式中的单例模式

    有时候在实际项目的开发中,我们会碰到这样一种情况,该类只允许存在一个实例化的对象,不允许存在一个以上的实例化对象,我们将这种情况称为Java设计模式中的单例模式.设计单例模式主要采用了Java的pri ...

  5. c语言 适配器模式例子,NodeJS设计模式总结【单例模式,适配器模式,装饰模式,观察者模式】...

    NodeJS设计模式总结[单例模式,适配器模式,装饰模式,观察者模式] 发布时间:2020-08-21 03:08:03 来源:脚本之家 阅读:117 作者:lucky芬 本文实例讲述了NodeJS设 ...

  6. Java设计模式探讨之单例模式

    单例模式是在平时的项目开发中比较常见的一种设计模式,使用比较普遍,网上的资料也是一抓一大把,小Alan也来凑凑热闹,为以后充实点设计模式相关的内容做个简单的开篇. 单例模式是一种创建对象的模式,用于产 ...

  7. 设计模式之一:单例模式(Singleton Pattern)

    写这个系列的文章,只为把所学的设计模式再系统的整理一遍.错误和不周到的地方欢迎大家批评.点击这里下载源代码. 什么时候使用单例模式 在程序运行时,某种类型只需要一个实例时,一般采用单例模式.为什么需要 ...

  8. 10.Java设计模式 工厂模式,单例模式

    Java 之工厂方法和抽象工厂模式 1. 概念 工厂方法:一抽象产品类派生出多个具体产品类:一抽象工厂类派生出多个具体工厂类:每个具体工厂类只能创建一个具体产品类的实例. 即定义一个创建对象的接口(即 ...

  9. 手撕设计模式之「单例模式」(详细解析)

    前言 单例模式主要用来保证系统中某个类的实例对象的唯一性,是最简单的一种设计模式,而且在面试中也经常会被问到,是非常值得我们去学习的.如果你们面试遇到了哪些设计模式的考察,也欢迎留言,我会及时发新的博 ...

  10. C#设计模式学习笔记-单例模式

    最近在学设计模式,学到创建型模式的时候,碰到单例模式(或叫单件模式),现在整理一下笔记. 在<Design Patterns:Elements of Resuable Object-Orient ...

最新文章

  1. 基于JavaWeb实现就业管理系统
  2. 2018.6.8-岁岁年年人不同
  3. UINavigationController使用的一些技巧
  4. UVa 11762 (期望 DP) Race to 1
  5. 装配图中齿轮的画法_装配图的规定画法 和特殊画法
  6. 【 .NET Core 3.0 】框架之十 || AOP 切面思想
  7. 配置Apache+Php+PDT(Zend Debugger)
  8. 100个最常用的PHP函数(建议收藏)
  9. ui设计 原则 要素_ui设计原则
  10. 远大驾校 考驾照 报名 科目一 科目二 科目三 科目四 视频
  11. HikariDataSource 配置详解
  12. python win32gui模块详解_Python笔记_第二篇_面向过程_第二部分_4.常用模块的简单使用_窗体控制模块(win32con、win32gui)...
  13. intel32/ctor.dll mysql_ctor.dll,下载,简介,描述,修复,等相关问题一站搞定_DLL之家
  14. 解决IE浏览器无法删除证书的问题
  15. P2676 [USACO07DEC]Bookshelf B
  16. ThinkPad T14、ThinkPadT16 2022款 评测
  17. 【全】各种颜色对应的 Hex code 和对应的 RGB 值
  18. python 图像变化检测_霍夫变换检测图像直线算法python实现
  19. 一分钟教会你pdf如何转为PPT,简单易上手
  20. Xshell和Xftp的安装与使用教程

热门文章

  1. oracle数据库解锁表
  2. Linux bunzip2命令:bz2格式的解压缩命令
  3. SpringBoot—整合log4j2入门和log4j2.xml配置详解
  4. 媒体控件的暂停与播放 0130 winform
  5. 前端开发 表格的补充 注释 标签的嵌套规则 0228
  6. mysql进阶-01-视图
  7. python-函数-局部变量与全局变量
  8. TIDB GC life time is shorter than transaction duration解决方法
  9. SCCM 2016 配置管理系列(Part4)
  10. 第 22 期:有序遍历语法