.NET单例模式-------各种写法&&验证

前言

    单例模式对大家来说都不陌生,也很容易搞懂其原理,本篇文章也不提供单例模式的详细原理解析,本篇文章的目的是展示在C#中单例模式的各种实现方案(不完全,只是最通用的方式)以及其特点的验证(是不是真的线程安全,是不是真的延迟初始化?),写单例模式的文章都很多了,各种语言,但是很多地方都只说:本方式支持多线程、支持延迟初始化等,也有很多也提供为什么支持,下面我对所有大家通常使用的几种单例模式方案进行讲解和验证!有哪里不对的地方,希望能得到尊敬的读者们拍砖反馈,觉得好,顺带推荐一下,谢谢。

简单原理解析

    单例模式,目标在于确保一个类仅仅能产生一个实例,并且提供一个全局访问点,获取该实例。

   无论哪一种单例模式变种,都离不开制作步骤这个中心。就好像无论哪家鸡爪店,其制作鸡爪方法都大同小异(都要先拿到鸡爪,洗鸡爪,弄熟鸡爪)。我们单例模式其实一样,其中心步骤包括:限制外部new出该对象的实例,内部提供该类型的一个唯一对象,提供一个全局访问点让外界获取到该唯一对象的实例进行操作。

   其实就这么简单,下面我要分析4个主要变种单例模式并且分别进行验证。

准备工作

    我先提供一个大概框架给大家,方便用于测试,也可以不下载,继续看下去。   测试模板下载

    提供的模板很简单,只有一个类Person,下面给出要点:

    1.构造函数是私有的(避免new出新实例)。

    2.在构造函数里,我写的Console.WriteLine(主要是观察这个类的实例是何时初始化的,初始化了多少次)。

    3.静态方法getName()的作用是:在还没有通过全局访问点获取实例之前,调用这个getName方法,内部的实例会不会被初始化,如果不会,证明延迟初始化了,如果会,证明没有延迟初始化。

    下面先给出一个例子,这个例子是饿汉式单例模式。

public class Person
    {
        /*饿汉式单例(线程安全,不支持延迟初始化)*/         //初始化的时候会有反应,应用于延迟初始化的验证
        private Person() {
            Console.WriteLine("我初始化了");
        }
        private static String name = "Jarvin";
        //内部的唯一实例
        private static Person instance = new Person();
        //全局访问点,用于获取唯一实例
        public static Person getInstance()
        {
            return instance;
        }         //实例方法
        public void Say()
        {
            Console.WriteLine("我是{0}",name);
        }
        /*静态的方法,应用于延迟初始化验证
         * 如果调用该方法之前还没初始,延迟初始化
         * 如果调用该方法之前初始化了,没有延迟初始化
         */
        public static String getName()
        {
            return name;
        }
        
    }

   测试的方式,要点:

    1.测试是否延迟初始化:测试方法是先调用Person.getName(),看结果返回name之前有没有被初始化来判断。

    2.测试线程安全:开3个多线程新任务,任务内容是获取唯一实例,并且调用实例方法。

  下面给出Main方法的代码:

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Person.getName());
            Console.WriteLine("下面进入多线程模式");
            for (int i = 0; i < 3; i++)
            {
                Task.Factory.StartNew(letPersonSay);
            }
            Console.ReadKey();
        }
        private static void letPersonSay()
        {
            Person emperor = Person.getInstance();
            emperor.Say();
        }
    }

            注意:单例模式秀中中出现的以下代码只是测试需要使用,在正式的使用场景要去掉。

int i=;
while (i > )
{ i--; }

单例模式秀

   1.饿汉式单例

        初步判断:不支持延迟初始化,线程安全。

private Person() {
Console.WriteLine("我初始化了");
}
private static String name = "Jarvin";
private static Person instance = new Person();
public static Person getInstance()
{
int i = ;
while (i > )
{ i--; }
return instance;
} public void Say()
{
Console.WriteLine("我是{0}",name);
}
public static String getName()
{
return name;
}

        验证:

        分析结果:在静态方法执行之前(Jarvin字符串)先初始化,不支持延迟初始化。然后进入多线程,没有问题。验证通过。

   2.懒汉式单例

        初步判断:支持延迟初始化,线程不安全。

private Person() {
Console.WriteLine("我初始化了");
}
private static String name = "Jarvin";
private static Person instance;
public static Person getInstance()
{
if (instance == null)
{
int i=;
while (i > )
{ i--; }
instance = new Person();
}
return instance;
} public void Say()
{
Console.WriteLine("我是{0}",name);
}
public static String getName()
{
return name;
}

        验证:

        分析结果:在调用静态方法之前并没有先初始化,所以支持延迟初始化。进入多线程以后,有出现两次初始化,创建了两个Person类实例,线程不安全。验证通过。

   3.内部类式单例

        初步判断:支持延迟初始化,线程安全

private Person()
{
Console.WriteLine("我初始化了");
}
public static Person getInstance()
{
return SingleHelper.GetEmperor();
}
private class SingleHelper
{
private static Person emperor = new Person();
public static Person GetEmperor()
{
int i = ;
while (i > )
{ i--; }
return emperor;
}
}
private static string name = "Jarvin"; public void Say()
{
Console.WriteLine("我是{0}", name);
}
public static String getName()
{
return name;
}

        验证:

            分析结果:在调用静态方法之前并没有先初始化,所以支持延迟初始化。进入多线程以后,只初始化一次,线程安全。验证通过。

   4.双检查式单例

        初步判断:支持延迟初始化,线程安全

private Person()
{
Console.WriteLine("我初始化了");
}
public static object Flag = new object();
public static Person me;
public static Person getInstance()
{
if (me == null)
{
lock (Flag)
{
if (me == null)
{
int i = ;
while (i > )
{ i--; }
me = new Person();
}
}
}
return me;
}
private static string name = "Jarvin"; public void Say()
{
Console.WriteLine("我是{0}", name);
}
public static String getName()
{
return name;
}

        验证:

            分析结果:在调用静态方法之前并没有先初始化,所以支持延迟初始化。进入多线程以后,只初始化一次,线程安全。验证通过。

总结

    其实单例模式非常简单,聪明的读者们看到这里应该对大概通过的这四种单例,以及其特性都了解了。见笑啦,下面提供全部测试的源码,有兴趣的可以收藏。

完整Demo下载

.NET单例模式-------各种写法&&验证的更多相关文章

  1. iOS开发笔记-两种单例模式的写法

    iOS开发笔记-两种单例模式的写法   单例模式是开发中最常用的写法之一,iOS的单例模式有两种官方写法,如下: 不使用GCD #import "ServiceManager.h" ...

  2. IOS 单例模式的写法

    iOS的单例模式有两种官方写法,如下: 1)不使用GCD的方式 #import "Manager.h" static Manager *manager; @implementati ...

  3. 【原】ios下比较完美的单例模式,已验证

    网上关于ios单例模式实现的帖子已经很多了,有很多版本,里面有对的也有不对的.我在使用过程中很难找到一个比较完美的方法,索性自己写一个吧,经过项目验证是比较合理的一个版本. static PRAuto ...

  4. iOS单例模式(Singleton)写法简析

    单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模式的要点有三个:一是某个类只能有一个实例: ...

  5. 【.NET】单例模式标准写法

    public sealed class Singleton { private static Singleton instance = null; static readonly object pad ...

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

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

  7. java单例模式的几种写法比较

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

  8. java单例模式等一些程序的写法....持续更新...

    一.单例模式的写法: public class MyFactory { /** * 饿汉式 */ private static MyFactory instance = new MyFactory() ...

  9. c# 单例模式(Single);单例模式的5种写法

    单例模式(Singleton Pattern): 在平时的开发中,可能会用到单例模式,许多java的笔试题中也会叫笔试者写出单例模式的那几种写法并且分析.那么下面就来轻轻地探讨一下,最简单的设计模式, ...

随机推荐

  1. Unity3D学习笔记——递归+非递归遍历GameObject的子物体

    在Unity3D中没有提供直接的方法获取某个GameObject的子GameObject,但是所有的GameObject都有transform对象,所以,一般是通过获取子GameObject的tran ...

  2. 【BZOJ】【3207】花神的嘲讽计划 I

    字符串Hash+可持久化线段树 好神奇的转化…… 蒟蒻一开始还去想AC自动机去了……然而由于a[i]的范围是小于等于n,怎么也想不出一个时间复杂度合理的方法 膜拜了题解0.0原来是字符串Hash! 首 ...

  3. 【BZOJ】【1042】【HAOI2008】硬币购物

    DP+容斥原理 sigh……就差一点…… 四种硬币的数量限制就是四个条件,满足条件1的方案集合为A,满足条件2的方案集合为B……我们要求的就是同时满足四个条件的方案集合$A\bigcap B\bigc ...

  4. 【BZOJ】【2424】【HAOI2010】订货

    网络流/费用流 比较简单的题……我一开始想成像软件开发那题一样的做法了……就是每天拆点,S->i (INF,0) .i+n->T (u[i],0) 然后处理购入 S->i+n (IN ...

  5. javascript遍历子元素

    最近写代码时需要获取符合某些条件的节点子元素,用firstChild之类的方法会包含文本节点,所以包装了一个简单的类: //子元素遍历器 function ElementWalker(node) { ...

  6. href=#与href=javascriptvoid(0)的区别

    #"包含了一个位置信息 默认的锚点是#top 也就是网页的上端 而javascript:void(0)  仅仅表示一个死链接 这就是为什么有的时候页面很长浏览链接明明是#可是跳动到了页首 而 ...

  7. Sqli-labs less 36

    Less-36 我们直接看到36关的源代码 上面的check_quotes()函数是利用了mysql_real_escape_string()函数进行的过滤. mysql_real_escape_st ...

  8. vi/vim使用指北 ---- Learning the vi and Vim Editors 读书 笔记

    vi/vim作为liux系统下最强大,最流行的文本编辑器之一.边看<Learning the vi and vim Editor>边学习vim,顺便做写简单的笔记,供以后查询. 没看这本书 ...

  9. WCF 传输和接受大数据

    向wcf传入大数据暂时还没找到什么好方案,大概测了一下传输2M还是可以的,有待以后解决. 接受wcf传回的大数据,要进行web.config的配置,刚开是从网上搜自己写进行配置,折磨了好长时间. 用以 ...

  10. C#两种创建快捷方式的方法

    C#两种创建快捷方式的方法http://www.cnblogs.com/linmilove/archive/2009/06/10/1500989.html