23种设计模式

一、创建型

1,AbstractFactory(抽象工厂,对象模式)

2,Builder(建造者,对象模式)

3,Factory Method(工厂方法,类创模式)

4,Prototype(原型,对象模式)

5,Singleton(单例,对象模式)

二、结构型

1,Adapter(适配器,类模式)

2,Bridge(桥接,对象模式)

3,Composite(组合,对象模式)

4,Decorator(装饰,对象模式)

5,Facade(外观,对象模式)

6,Flyweight(享元,对象模式)

7,Proxy(代理,对象模式)

三、行为型

1,Chain of Responsibility(职责链,对象模式)

2,Command(命令,对象模式)

3,Interpreter(解释器,类模式)

4,Iterator(迭代器,对象模式)

5,Mediator(中介者,对象模式)

6,Memento(备忘录,对象模式)

7,Observer(观察者,对象模式)

8,State(状态,对象模式)

9,Strategy(策略,对象模式)

10,Template Method(模板方法,类模式)

11,Visitor(访问者,对象模式)

单例模式(Singleton Pattern)【使用频率:★★★★★】

1.概述:

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。

单例指的是只能存在一个实例的类,在C#中,更准确的说法是在每个AppDomain之中只能存在一个实例的类,它是软件工程中使用最多的几种模式之一。在第一个使用者创建了这个类的实例之后,其后需要使用这个类的就只能使用之前创建的实例,无法再创建一个新的实例。

一、非线程安全

public sealed class Singleton
{
private static Singleton instance = null; private Singleton()
{ } public static Singleton instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}

这种方法不是线程安全的,会存在两个线程同时执行if (instance == null)并且创建两个不同的instance,后创建的会替换掉新创建的,导致之前拿到的reference为空。

二、简单的线程安全实现

public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object(); private Singleton()
{
} public static Singleton Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
}

相比较于实现一,这个版本加上了一个对instance的锁,在调用instance之前要先对padlock上锁,这样就避免了实现一中的线程冲突,该实现自始至终只会创建一个instance了。但是,由于每次调用Instance都会使用到锁,而调用锁的开销较大,这个实现会有一定的性能损失。

注意:这里我们使用的是新建一个private的object实例padlock来实现锁操作,而不是直接对Singleton进行上锁。直接对类型上锁会出现潜在的风险,因为这个类型是public的,所以理论上它会在任何code里调用,直接对它上锁会导致性能问题,甚至会出现死锁情况。

Note: C#中,同一个线程是可以对一个object进行多次上锁的,但是不同线程之间如果同时上锁,就可能会出现线程等待,或者严重的会出现死锁情况。因此,我们在使用lock时,尽量选择类中的私有变量上锁,这样可以避免上述情况发生。

存在问题:

问题貌似得以解决,事实并非如此。如果使用以上代码来实现单例,还是会存在单例对象不唯一。原因如下:

假如在某一瞬间线程A和线程B都在调用Instance属性,此时instance对象为null值,均能通过instance == null的判断。由于实现了lock加锁机制,线程A进入lock锁定的代码中执行实例创建代码,线程B处于排队等待状态,必须等待线程A执行完毕后才可以进入lock锁定代码。但当A执行完毕时,线程B并不知道实例已经创建,将继续创建新的实例,导致产生多个单例对象,违背单例模式的设计思想,因此需要进行进一步改进,在lock中再进行一次(instance == null)判断,这种方式称为双重检查锁定(Double-Check Locking)。

三、双重验证的线程安全实现

public sealed class Singleton
{
private volatile static Singleton instance = null;
private static readonly object padlock = new object(); private Singleton()
{
} public static Singleton Instance
{
get
{
if (instance == null)
{
// 当第一个线程运行到这里时,此时会对locker对象 "加锁",
// 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,
// 该线程就会挂起等待第一个线程解锁
// 第一个线程运行完之后, 会对该对象"解锁"
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}

如果使用双重检查锁定来实现单例类,需要在静态成员变量instance之前增加修饰符volatile,被volatile修饰的成员变量可以确保多个线程都能够正确处理。

volatile的使用场景

多个线程同时访问一个变量,CLR为了效率,允许每个线程进行本地缓存,这就导致了变量的不一致性。volatile就是为了解决这个问题,volatile修饰的变量,不允许线程进行本地缓存,每个线程的读写都是直接操作在共享内存上,这就保证了变量始终具有一致性。

性能测试

为了比较这几种实现的性能,我做了一个小测试,循环拿这些实现中的单例9亿次,每次调用instance的方法执行一个count++操作,每隔一百万输出一次。

3. 模式优缺点

3.1 优点

  • 提供了对唯一实例的受控访问;
  • 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能;
  • 可以根据实际情况需要,在单例模式的基础上扩展做出双例模式,多例模式;

3.2 缺点

  • 单例类的职责过重,里面的代码可能会过于复杂,在一定程度上违背了“单一职责原则”。
  • 如果实例化的对象长时间不被利用,会被系统认为是垃圾而被回收,这将导致对象状态的丢失。

4. 适用场景

  • 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
  • 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

设计模式-1 单例模式 SingletonPattern的更多相关文章

  1. iOS设计模式(02):单例模式

    iOS设计模式(02):单例模式 singleton-design-pattern 什么是单例模式? 单例模式是一个类在系统中只有一个实例对象.通过全局的一个入口点对这个实例对象进行访问.在iOS开发 ...

  2. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

  3. GJM : C#设计模式(1)——单例模式

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  4. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  5. 每天一个设计模式-4 单例模式(Singleton)

    每天一个设计模式-4 单例模式(Singleton) 1.实际生活的例子 有一天,你的自行车的某个螺丝钉松了,修车铺离你家比较远,而附近的五金店有卖扳手:因此,你决定去五金店买一个扳手,自己把螺丝钉固 ...

  6. 设计模式之单例模式的简单demo

    /* * 设计模式之单例模式的简单demo */ class Single { /* * 创建一个本类对象. * 和get/set方法思想一样,类不能直接调用对象 * 所以用private限制权限 * ...

  7. 设计模式之单例模式——Singleton

                        设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...

  8. 10月27日PHP加载类、设计模式(单例模式和工厂模式)、面向对象的六大原则

    加载类可以使用include.require.require_once三种中的任意一种,每个关键字都有两种方法,但是这种方法的缺点是需要加载多少个php文件,就要写多少个加载类的方法.一般也就需要加载 ...

  9. java 23 - 2 设计模式之单例模式

    单例模式:保证类在内存中只有一个对象. 如何保证类在内存中只有一个对象呢?  A:把构造方法私有  B:在成员位置自己创建一个对象  C:通过一个公共的方法提供访问 单例模式之饿汉式: (一进来就造对 ...

  10. [转]JAVA设计模式之单例模式

    原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主 ...

随机推荐

  1. .NET使用QuestPDF高效地生成PDF文档

    前言 在.NET平台中操作生成PDF的类库有很多如常见的有iTextSharp.PDFsharp.Aspose.PDF等,今天我们分享一个用于生成PDF文档的现代开源.NET库:QuestPDF,本文 ...

  2. java两个list取交集

    直接上代码 List<Integer> list1 = new ArrayList<>(); list1.add(1); list1.add(2); list1.add(3); ...

  3. GPT应用开发:GPT插件开发指南

    欢迎阅读本系列文章!我将带你一起探索如何利用OpenAI API开发GPT应用.无论你是编程新手还是资深开发者,都能在这里获得灵感和收获. 本文,我们将继续展示聊天API中插件的使用方法,让你能够轻松 ...

  4. vue插件实现循环滚动列表——vue-seamless-scroll

    https://blog.csdn.net/weixin_45389051/article/details/106379832?utm_medium=distribute.pc_relevant.no ...

  5. C#排序算法6:快速排序

    快速排序由C. A. R. Hoare在1960年提出.它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分 ...

  6. C++ Lambda 表达式递归写法

    今天看到一篇博客介绍使用 Lambda 表达式递归计算 n!.使用了 C++14 的 generic lambda,给 Lambda 表达式加了一个模板参数,在函数调用的时候将 Lambda 表达式作 ...

  7. 问题--C++单例模式中唯一对象初始化时关于在类外调用私有的无参构造问题

    1.问题 在单例模式中初始化单例对象Person* Person::signal= new Person; 这一步在类外,而new Person需要调用私有的无参构造,但是只有在类内部才能调用私有函数 ...

  8. 例2.9 建立一个带头结点的线性链表,用以存放输人的二进制数,链表中每个结点的data域存放一个二进制位。并在此链表上实现对二进制数加1的运算。

    1.题目 例2.9建立一个带头结点的线性链表,用以存放输人的二进制数,链表中每个结点的data域存放一个二进制位.并在此链表上实现对二进制数加1的运算. 2.算法分析 3.代码 /* 二进制加1 */ ...

  9. [转帖]记一次sst文件损坏修复过程

    https://tidb.net/blog/54e388c8 [2023-07-14 14:26:28]应用系统报警删除数据失败,查看日志报Region is unavailable,同时企业微信群也 ...

  10. [转帖]Jmeter跨线程组传参

    https://www.cnblogs.com/a00ium/p/10462576.html   我们知道,同一线程组中可以通过"正则表达式提取器"获取其中一个取样器的响应结果中的 ...