C# 设计模式系列教程-单例模式

1. 描述:

  保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2. 单例模式主要有3个特点,:

  2.1 单例类确保自己只有一个实例。
  2.2 单例类必须自己创建自己的实例。
  2.3 单例类必须为其他对象提供唯一的实例。

3. 实现方式:懒汉单例类和饿汉单例类

  3.1 懒汉式单例类
    对于懒汉模式,我们可以这样理解:该单例类非常懒,只有在自身需要的时候才会行动,从来不知道及早做好准备。它在需要对象的时候,才判断是否已有对象,如果没有就立即创建一个对象,然后返回,如果已有对象就不再创建,立即返回。
懒汉模式只在外部对象第一次请求实例的时候才去创建。

  3.2 饿汉式单例
    对于饿汉模式,我们可以这样理解:该单例类非常饿,迫切需要吃东西,所以它在类加载的时候就立即创建对象。

  3.3 懒汉模式和饿汉模式的优缺点:
    懒汉模式,它的特点是运行时获得对象的速度比较慢,但加载类的时候比较快。它在整个应用的生命周期只有一部分时间在占用资源。
    饿汉模式,它的特点是加载类的时候比较慢,但运行时获得对象的速度比较快。它从加载到应用结束会一直占用资源。
    这两种模式对于初始化较快,占用资源少的轻量级对象来说,没有多大的性能差异,选择懒汉式还是饿汉式都没有问题。但是对于初始化慢,占用资源多的重量级对象来说,就会有比较明显的差别了。所以,对重量级对象应用饿汉模式,类加载时速度慢,但运行时速度快;懒汉模式则与之相反,类加载时速度快,但运行时第一次获得对象的速度慢。
    从用户体验的角度来说,我们应该首选饿汉模式。我们愿意等待某个程序花较长的时间初始化,却不喜欢在程序运行时等待太久,给人一种反应迟钝的感觉,所以对于有重量级对象参与的单例模式,我们推荐使用饿汉模式。
    而对于初始化较快的轻量级对象来说,选用哪种方法都可以。如果一个应用中使用了大量单例模式,我们就应该权衡两种方法了。轻量级对象的单例采用懒汉模式,减轻加载时的负担,缩短加载时间,提高加载效率;同时由于是轻量级对象,把这些对象的创建放在使用时进行,实际就是把创建单例对象所消耗的时间分摊到整个应用中去了,对于整个应用的运行效率没有太大影响。

4. 代码实现:

  4.1 懒汉式

  public class Singleton
  {
    private static Singleton m_Instance;

    private Singleton()
    {
      // 将默认构造函数定义为私有,防止外部调用它实例化别的对象
    }

    public static Singleton GetInstance()
    {

      if (m_Instance == null)
      {
        m_Instance = new Singleton();
      }

      return m_Instance;
    }
  }

  4.2 饿汉式

  // 定义为sealed防止派生,因为派生可能增加实例
  public sealed class Singleton
  {
    private static readonly Singleton m_Instance = new Singleton();
    private Singleton()
    {
      // 将默认构造函数定义为私有,防止外部调用它实例化别的对象
    }

    public static Singleton GetInstance()
    {
      return m_Instance;
    }
  }

5. 模式总结

  5.1 优点:
    防止在应用程序中实例化多个对象。这就节约了开销,每个实例都要占用一定的内存,创建对象时需要时间和空间。

  5.2 缺点:

  5.3 适用场合:
    5.3.1 控制资源的使用,通过线程同步来控制资源的并发访问;
    5.3.2 控制实例产生的数量,达到节约资源的目的。
    5.3.3 作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。

  5.4 对设计原则的支持:

    使用单例模式最核心的一点是体现了面向对象封装特性中的“单一职责”原则。

6. 补充: 在多线程开放过程中,对使用懒汉单例模式应防止两个线程同时去实例化对象,这是有可能的。

下面给出解决方案

  6.1 使用锁机制

  public class Singleton
  {
    private static Singleton m_Instance;

    static readonly object o = new object();

    private Singleton()
    {
      // 将默认构造函数定义为私有,防止外部调用它实例化别的对象
    }

    public static Singleton GetInstance()
    {
      lock (o)
      {
        if (m_Instance == null)
        {
          m_Instance = new Singleton();
        }
      }

      return m_Instance;
    }
  }

  使用锁机制可以防止两个线程同时创建对象,但这里有个性能问题,每当一个线程访问GetInstance()这个方法是,都要加锁,这其实是没必要的。

  6.2 双重锁定

  public class Singleton
  {
    private static Singleton m_Instance;

    static readonly object o = new object();

    private Singleton()
    {
      // 将默认构造函数定义为私有,防止外部调用它实例化别的对象
    }

    public static Singleton GetInstance()
    {
      // 这里增加了一个判断实例是否存在,只有在不存在时才给加锁,也就是在这个实例的生命周期中只加过一次锁
      if (m_Instance == null)
      {
        lock (o)
        {
          if (m_Instance == null)
          {
            m_Instance = new Singleton();
          }
        }
      }

      return m_Instance;
    }
  }

  双重锁定保证了实例在它的生命周期中只被锁定一次,因而它对性能不会有影响。

以上就是本文的全部内容,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • c#单例模式(Singleton)的6种实现

    1.1.1 摘要 在我们日常的工作中经常需要在应用程序中保持一个唯一的实例,如:IO处理,数据库操作等,由于这些对象都要占用重要的系统资源,所以我们必须限制这些实例的创建或始终使用一个公用的实例,这就是我们今天要介绍的--单例模式(Singleton). 使用频率高 单件模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点. 1.1.2 正文 图1单例模式(Singleton)结构图 单例模式(Singleton)是几个创建模式中最对立的一个,它的主要特点不是根据用户

  • C#中单例模式的三种写法示例

    第一种最简单,但没有考虑线程安全,在多线程时可能会出问题,不过俺从没看过出错的现象,表鄙视我-- 复制代码 代码如下: public class Singleton {     private static Singleton _instance = null;     private Singleton(){}     public static Singleton CreateInstance()     {         if(_instance == null)         {  

  • C#窗口实现单例模式的方法

    主要是应对这种需求:软件只允许启动一次. 将这个问题转化一下,可以这样描述:对于一个软件,在启动一个进程之后,不允许启动其它进程,如果第二次打开程序,就把已经启动的那个进程的窗口放到最前端显示. C# winfrom应用在启动之后会首先执行program.cs里的代码,所以需要在这里下手.启动后,检测是否有相同进程名的进程,如果有,就把那个进程的窗口提到前端,然后关闭自己. 用法:把你的program.cs改造成这个样子: static class Program { //windows api

  • C# 设计模式之单例模式归纳总结

    优缺点  优点: 一.实例控制 单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例. 二.灵活性 因为类控制了实例化过程,所以类可以灵活更改实例化过程. 缺点: 一.开销 虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销.可以通过使用静态初始化解决此问题. 二.可能的开发混淆 使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象.因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自

  • 举例讲解C#编程中对设计模式中的单例模式的运用

    单例模式的介绍 说到单例模式,大家第一反应应该就是--什么是单例模式?,从"单例"字面意思上理解为--一个类只有一个实例,所以单例模式也就是保证一个类只有一个实例的一种实现方法罢了,下面给出单例模式的一个官方定义:确保一个类只有一个实例,并提供一个全局访问点.为了帮助大家更好地理解单例模式,大家可以结合下面的类图来进行理解,以及后面也会剖析单例模式的实现思路: 为什么会有单例模式 看完单例模式的介绍,自然大家都会有这样一个疑问--为什么要有单例模式的?它在什么情况下使用的?从单例模式的

  • C#单例模式(Singleton Pattern)实例教程

    本文以实例形式讲述了C#单例模式(Singleton Pattern)的实现方法,分享给大家供大家参考.具体实现方法如下: 一般来说,当从应用程序全局的角度来看,如果只允许类的一个实例产生,就可以考虑单例模式. 1.即时加载的单例模式 把类的实例赋值给类的一个静态字段. class Program { static void Main(string[] args) { Logger log = Logger.GetInstance(); log.WriteToFile(); Console.Re

  • C#设计模式之单例模式实例讲解

    前言 最近开始花点心思研究下设计模式,主要还是让自己写的代码可重用性高.保证代码可靠性.所谓设计模式,我找了下定义:是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.毫无疑问,设计模式于己于他人于系统都是多赢的:设计模式使代码编制真正工程化:设计模式是软件工程的基石脉络,如同大厦的结构一样. 为什么要提倡"Design Pattern(设计模式)"? 根本原因是为了代码复用,增加可维护性.因此这次我们来学习下设计模式,最后会通过C#语言来实现这些设计模式作为例子,深刻

  • 浅谈C#单例模式的实现和性能对比

    简介 单例指的是只能存在一个实例的类(在C#中,更准确的说法是在每个AppDomain之中只能存在一个实例的类,它是软件工程中使用最多的几种模式之一.在第一个使用者创建了这个类的实例之后,其后需要使用这个类的就只能使用之前创建的实例,无法再创建一个新的实例.通常情况下,单例会在第一次被使用时创建.本文会对C#中几种单例的实现方式进行介绍,并分析它们之间的线程安全性和性能差异. 单例的实现方式有很多种,但从最简单的实现(非延迟加载,非线程安全,效率低下),到可延迟加载,线程安全,且高效的实现,它们

  • C#单例模式(Singleton Pattern)详解

    (新手写博客,主要是对自己学习的归纳总结.会对很多小细节详解.) 单例模式的定义: 确保一个类只有一个实例,并提供一个全局访问点. 首先实例大家应该都明白就是类生成对象的过程简单的就是String s=new String(),则s就是个实例. Q:如何只生成一个实例? A:1)首先必须将构造函数变为私有从而防止其他类实例化,并且只能有一个构造函数.因为系统会默认一个无参构造函数,而且默认public访问修饰符. 所以必须写一个私有无参让默认无效.(通常单例模式都是不带形参的) 2)在该类中声明

  • C# 设计模式系列教程-单例模式

    1. 描述: 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 2. 单例模式主要有3个特点,: 2.1 单例类确保自己只有一个实例. 2.2 单例类必须自己创建自己的实例. 2.3 单例类必须为其他对象提供唯一的实例. 3. 实现方式:懒汉单例类和饿汉单例类 3.1 懒汉式单例类 对于懒汉模式,我们可以这样理解:该单例类非常懒,只有在自身需要的时候才会行动,从来不知道及早做好准备.它在需要对象的时候,才判断是否已有对象,如果没有就立即创建一个对象,然后返回,如果已有对象就不再创建,立即返

  • Android设计模式系列之单例模式

    单例模式,可以说是GOF的23种设计模式中最简单的一个. 这个模式相对于其他几个模式比较独立,它只负责控制自己的实例化数量单一(而不是考虑为用户产生什么样的实例),很有意思,是一个感觉上很干净的模式,本人很喜欢这个模式. android中很多地方都用到了单例模式,本文以输入法管理者InputMethodManager为例,展开分析. 单例模式,Singleton Pattern,能够以其特有的优势,替代系统中全局变量,应用非常广泛. 1.意图 保证一个类仅有一个实例,并提供一个访问它的全局访问点

  • C# 设计模式系列教程-抽象工厂模式

    1. 概述 抽象工厂模式为一个产品家族提供了统一的创建接口.当需要这个产品家族的某一系列的时候,可以从抽象工厂中选出相对应的系列来创建一个具体的工厂类别. 2. 抽象工厂模式中的角色 2.1 抽象工厂(AbstractFactory):担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的. 2.2 具体工厂(ConcreteFactory):这个角色直接在客户端的调用下创建产品的实例.这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的. 2.3 抽象产品

  • C# 设计模式系列教程-建造者模式

    1. 概述 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 2. 建造者模式中的角色 2.1 建造者(Builder):为创建一个产品对象的各个部件指定抽象接口. 2.2 具体建造者(ConcreteBuilder):实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并 提供一个检索产品的接口. 2.3 指挥者(Director):指挥并构造一个使用Builder接口的对象. 2.4 产品(Product):

  • C# 设计模式系列教程-简单工厂模式

    1. 概述: 将一个具体类的实例化交给一个静态工厂方法来执行,它不属于GOF的23种设计模式,但现实中却经常会用到 2. 模式中的角色 2.1 工厂类(Simple Factory): 只包含了创建具体类的静态方法. 2.2 抽象产品(Product):定义简单工厂中要返回的产品. 2.3 具体产品(ConcreteProduct):具体产品. 3. 模式解读 3.1 简单工厂模式的一般化类图 3.2 简单工厂模式的代码实现 /// <summary> /// 简单工厂类,用sealed修饰,

  • C# 设计模式系列教程-适配器模式

    1. 概述 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作. 2. 解决的问题 即Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作. 3. 模式中的角色 3.1 目标接口(Target):客户所期待的接口.目标可以是具体的或抽象的类,也可以是接口. 3.2 需要适配的类(Adaptee):需要适配的类或适配者类. 3.3 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接

  • C# 设计模式系列教程-组合模式

    1. 概述 将对象组合成树形结构以表示"部分-整体"的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性. 2. 解决的问题 当希望忽略单个对象和组合对象的区别,统一使用组合结构中的所有对象(将这种"统一"性封装起来). 3. 组合模式中的角色 3.1 组合部件(Component):它是一个抽象角色,为要组合的对象提供统一的接口. 3.2 叶子(Leaf):在组合中表示子节点对象,叶子节点不能有子节点. 3.3 合成部件(Composite):定义有枝

  • C# 设计模式系列教程-原型模式

    1. 概述 通过复制一个已经存在的实例来创建一个新的实例.被复制的实例被称为原型,这个原型是可定制的. 2. 模式中的角色 2.1 抽象原型类(Abstract Prototype):提供一个克隆接口 2.2 具体原型类(Concrete Prototype): 及实现了克隆接口的具体原型类 3. 实例:求职网站上现在都支持多份简历,如果每创建一份简历都要从头至尾地填写一遍,那也是非常让人沮丧的事.其实针对我们的求职岗位的不同,不同的简历可能只要修改局部内容就可以了,而不用全部重新构建一份新的简

  • C# 设计模式系列教程-模板方法模式

    1. 概述 定义一个操作中的算法的骨架,而将步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤. 2. 模式中的角色 2.1 抽象类(AbstractClass):实现了模板方法,定义了算法的骨架. 2.2 具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法. 3. 模式解读 3.1 模板方法类图 3.2 模板方法模式代码实现 /// <summary> /// 抽象类 /// </summary> public ab

  • C# 设计模式系列教程-装饰模式

    1. 概述 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活. 原理:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数.装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法.修饰类必须和原来的类有相同的接口. 2. 模式中的角色 2.1 抽象构建(Component):定义一个抽象接口,用以给这些对象动态地添加职责. 2.2 具体构建(ConcreteComponent):定义一个具体的对象,也可以

随机推荐