单例模式(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. 【白话设计模式四】单例模式(Singleton)

    转自:https://my.oschina.net/xianggao/blog/616385 0 系列目录 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factor ...

  2. php设计模式笔记:单例模式

    php设计模式笔记:单例模式 意图: 保证一个类仅有一个实例,并且提供一个全局访问点 单例模式有三个特点: 1.一个类只有一个实例2.它必须自行创建这个实例3.必须自行向整个系统提供这个实例 主要实现 ...

  3. Java设计模式之《单例模式》及应用场景

    摘要: 原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6510196.html 所谓单例,指的就是单实例,有且仅有一个类实例,这个单例不应该 ...

  4. Java设计模式之【单例模式】

    Java设计模式之[单例模式] 何为单例 在应用的生存周期中,一个类的实例有且仅有一个 当在一些业务中需要规定某个类的实例有且仅有一个时,就可以用单例模式 比如spring容器默认初始化的实例就是单例 ...

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

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

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

    最近学习 设计模式,从单例模式入手 啥是单例模式: 要实现一个单例类的话,首先,肯定是不能让用户自行生产的,那就是说明不能让用户new,所以,就必须把构造函数设置成为私有的 因为静态变量的生命周期跟整 ...

  7. IOS设计模式浅析之单例模式(Singleton)

    说在前面 进入正式的设计模式交流之前,扯点闲话.我们在项目开发的过程中,经常会不经意的使用一些常见的设计模式,如单例模式.工厂方法模式.观察者模式等,以前做.NET开发的时候,认真拜读了一下程杰老师的 ...

  8. C#设计模式学习笔记-单例模式(转)

    C#设计模式学习笔记-单例模式 http://www.cnblogs.com/xun126/archive/2011/03/09/1970807.html 最近在学设计模式,学到创建型模式的时候,碰到 ...

  9. PHP 面向对象编程和设计模式 (3/5) - 单例模式和工厂模式

    PHP高级程序设计 学习笔记 2014.06.11 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容 ...

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

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

随机推荐

  1. VS code 的集成终端Integrated terminal 的颜色问题

    其实是默认终端的配色问题在使用vs code时,运行代码时,控制台是这样子的,搞得我很难受 一块一块的 其实是默认终端的配色问题 默认终端一般是powershell,还可以是cmd,或者git bas ...

  2. 【java面试】- 集合篇

    Java 集合概览 从下图可以看出,在Java中除了以Map结尾的类之外, 其他类都实现了Collection接口.并且,以Map结尾的类都实现了Map接口 List.Set.Map三者的区别 Lis ...

  3. [jvm] -- 判断对象是否死亡篇

    判断对象是否死亡的两种方法 引用计数法 给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1:当引用失效,计数器就减 1:任何时候计数器为 0 的对象就是不可能再被使用的. 优点: 简单 ...

  4. Linux内存大页设置

    实际环境中,遇到3次由于内存大页设置参数不合理或者错误,导致系统内存不足,或者数据库内存不足的问题. 按照如下方式,推荐设置大页参考下发设置! 参考HugePages on Oracle Linux ...

  5. 题解 洛谷 P4899 【[IOI2018] werewolf 狼人】

    先考虑狼形,其只能走编号小于\(R\)的点.若将每条边赋边权为其两端点编号的较大值,然后按最小生成树的顺序构建\(Kruskal\)重构树. 那么从原图的一个点\(x\)在树上倍增,到达满足要求且深度 ...

  6. SpringBoot + Spring Cloud Consul 服务注册和发现

    什么是Consul Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其它分布式服务注册与发现的方案,Consul 的方案更"一站式" ...

  7. 利用74HC595实现的流水灯 Arduino

    int big = 2; int push = 3; int datain = 4; void setup() { Serial.begin(9600); pinMode(big, OUTPUT); ...

  8. 手动触发浏览器resize

    今天做echarts图表 发现饼图不能居中,resize之后才会居中. 于是想手动触发resize方法,但是不改变浏览器窗口 JQ $(window).trigger('risize'); JS    ...

  9. 面试题四十三:在1~n整数中1出现的次数

    方法一:直观来看,遍历1到n,每个数去做%10的循环判断 int Number1_B_1toN( int n){ int sum=0; for(int i=1;i<=n;i++){ int k= ...

  10. Merging 和 Rebasing 的大比拼

    虽然 merging 和 rebasing 在 git 中相似时,但他们提供不同的功能.为了让你的历史尽可能的干净和完整,你应该知道以下几点. git rebase 命令已 神奇的 Git voodo ...