单例模式以及在C#中的使用
下面做一些简要的说明。
1.
单例模式(Singleton Pattern),又称作单件模式,当然也有一种诙谐的称谓:单身模式。在经典的GoF所著的《Design Patterns》一书中,对单例模式有着详尽的介绍,这本书网上有全文版本。
2.
单例模式的意图是保证一个类仅有一个实例,并且要提供一个全局访问点来访问这个实例。通常这个全局访问点是一个静态方法或者C#中的一个属性。
3.
在C#中,典型的单例模式实现方法可以如下:
public class Manager { private static Manager Mgr; //constructor must be private private Manager() { } //public and static, or you can change it to Property instead of Method. public static Manager GetInstance() { if (Mgr == null ) { Mgr = new Manager(); } return Mgr; } } |
当外部需要Manager
的实例时,可以调用GetInstance()
这个静态方法。由于Manager
类的构造器是私有的,这也就避免了其他方式实例化这个Manager
类。GetInstance()
方法内部的实现,保证了全局中只有一个Manager
实例。
4.
问题肯定不会这么简单就被解决,比如在多线程环境中,上述代码就会有很大的隐患。
- 有一种情况很常见:两个线程同时调用
GetInstance()
方法; - 当某一个线程由于
Mgr
为null
而进入条件判断代码块的时候,而恰恰还没有执行实例化一个Manager
对象,这时候另一个线程由于Mgr
为null
,所以也会进入这个条件语句中
上面两种情况,很显然都会创建Manager
实例,这也就违背了单例模式的意图了。
利用C#的特性,我们可以把一个线程先锁住(lock
),等到这个线程完成后,再让下一个线程访问GetInstance()
方法:
private static readonly object syncObject = new object (); //public and static, or you can change it to Property instead of Method. public static Manager GetInstance() { //double check if (Mgr == null ) { lock (syncObject) { if (Mgr == null ) { Mgr = new Manager(); } } } return Mgr; } |
代码中用到了双重检查锁定(double check locking)的技术,是为了提高性能考虑,因为C#中lock
语句是很耗性能的。第一道检查,是基于如果Mgr
不为null
的时候就不需要lock
了,提高性能。第二道检查,是基于两个线程同时通过第一道检查后,第一个线程解锁后,由于Mgr
此时已经不为null
,所以第二个线程就不用实例化Manager
了。
5.
单例模式有两种实现方式,主要基于构建的方式不同:
- 延迟初始化(Lazy Initialization),也叫“懒汉模式”:单例实例在第一次使用时被构建;
- 热初始化(Eager Initialization),也叫“恶汉模式”:单例实例在类加载时创建
前面创建单例模式的方式都属于延迟初始化。.NET 4.0以后提供了一个Lazy<T>
泛型类,可以被应用于这个场景,省却代码的编写量。
public class Manager { private static Lazy<Manager> mgr = new Lazy<Manager>(); //version of Thread Safe //private static Lazy<Manager> mgr = new Lazy<Manager>(true); private Manager() { } public static Manager GetInstance() { return mgr.Value; } } |
Lazy<T>
的构造器重载版本可以帮我们解决多线程的问题。
C#使用静态初始化来完成单例模式中的热初始化。需要注意的是,不需要考虑多线程的问题,因为CLR会自动解决多线程同步的问题。如果程序经常要用到这个实例,运用热初始化可以显著提高性能。
public class Manager { private static readonly Manager mgr = new Manager(); private Manager() { } public static Manager GetInstance() { return mgr; } } |
6.
StackOverflow中对于单例模式都是持否定态度的,比如这个:
In theory: when you need to restrict the instantiation of an object to one instance. In practice: never.
主要基于下面几个原因:
- 违反了单一职责原则
- 耦合度过大
- 单元测试基本无法进行
- 开发混淆,造成混乱。比如作为API提供的时候。
总之,
There‘s at most a can use but there no need.
文章来源:http://laobian.me/2013/02/singleton-pattern-with-csharp.html
单例模式以及在C#中的使用的更多相关文章
- 单例模式@Singleton在测试中的运用
前言 单例模式是一种比较常用的设计模式,目的是:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 测试种可能用到的场景 : 在很多时候,有些对象我们希望在整个程序只有一个实例,如线程池.数据库连 ...
- 单例模式读取properties配置文件中的信息
public class ConfigManager { private static ConfigManager config = null; //创建Properties文件 读取配 ...
- Objective-C中的单例模式
单例模式算是设计模式中比较简单的一种吧,设计模式不是只针对某种编程语言,在C++, Java, PHP等其他OOP语言也有设计模式,笔者初接触设计模式是通过<漫谈设计模式>了解 ...
- Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)
Java中的GOF23(23中设计模式)--------- 单例模式(Singleton) 在Java这这门语言里面,它的优点在于它本身的可移植性上面,而要做到可移植的话,本身就需要一个中介作为翻译工 ...
- Android中的单例模式
定义: 单例模式:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 使用场景: 确保某一个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一 ...
- java中的单例模式与doublecheck
转自: http://devbean.blog.51cto.com/448512/203501 在GoF的23种设计模式中,单例模式是比较简单的一种.然而,有时候越是简单的东西越容易出现问题.下面就单 ...
- java中的单例模式与静态类
单例模式与静态类(一个类,所有方法为静态方法)是另一个非常有趣的问题,在<Java中有关单例模式的面试问题>博文中露掉了,由于单例模式和静态类都具有良好的访问性,它们之间有许多相似之处,例 ...
- 设计模式 - Java中单例模式的6种写法及优缺点对比
目录 1 为什么要用单例模式 1.1 什么是单例模式 1.2 单例模式的思路和优势 2 写法① - 饥饿模式 2.1 代码示例 2.2 优缺点比较 3 写法② - 懒惰模式 3.1 代码示例 3.2 ...
- 设计模式(五): 简单而又不失其重要性的单例模式(Singleton Pattern)
上篇博客我们系统的介绍了三种工厂模式,今天我们就来介绍一下单例模式.单例模式虽然简单,但是还是比较重要的,是常用设计模式之一.在之前的博客<Objective-C中的单例模式>中介绍了Ob ...
随机推荐
- Erlang学习记录:运算符
数学运算符 说明 详细 符号 加减乘 +-* 浮点数除 结果为浮点数 / 整数除 除数和被除数都必须是整数,结果为整数 div 整数取余 rem 逻辑运算符 说明 符号 详细 and 前后两个值都为真 ...
- vim编码方式设置
建议vim的_vimrc文件里设置如下的编码方式: set encoding=utf-8 set fileencodings=ucs-bom,utf-8,cp936 set fileencoding= ...
- 关于FR4板一些重复的数据
介电常数:4.2-4.7 信号传输速度:表层 140~170 ps/inch, 内层 180 ps/inch
- Nacos v0.7.0:对接CMDB,实现基于标签的服务发现能力
Nacos近期发布了0.7.0版本,该版本支持对接第三方CMDB获取CMDB数据.使用Selector机制来配置服务的路由类型.支持单机模式使用MySQL数据库.上线Node.js客户端,并修复了一些 ...
- day 49 Bootstrap框架和inconfont、font-awesome使用
Bootstrap框架和inconfont.font-awesome使用 iconfont的使用:https://www.cnblogs.com/clschao/articles/10387580 ...
- PAT甲级——A1133 Splitting A Linked List【25】
Given a singly linked list, you are supposed to rearrange its elements so that all the negative valu ...
- 论文阅读-(CVPR 2017) Kernel Pooling for Convolutional Neural Networks
在这篇论文中,作者提出了一种更加通用的池化框架,以核函数的形式捕捉特征之间的高阶信息.同时也证明了使用无参数化的紧致清晰特征映射,以指定阶形式逼近核函数,例如高斯核函数.本文提出的核函数池化可以和CN ...
- linux sudo命令失败 提示sudo:/usr/bin/sudo 必须属于用户 ID 0(的用户)并且设置 setuid 位
sudo:/usr/bin/sudo 必须属于用户 ID 0(的用户)并且设置 setuid 位 一.前言 这是一个神奇的错误,缘由是因为有人将/usr/bin/sudo的权限改为777或其他. 解决 ...
- Python全栈开发:协程代码实例
协程代码1 #!/usr/bin/env python # -*- coding;utf-8 -*- # 导入协程模块 """ 协程工作原理 ""&q ...
- 【CQOI2015】选数
题面 Description 我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案.小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次 ...