这里写的代码,相当于《Head First 设计模式》的读书笔记,原书是java的,自己在学习的过程中将其翻译为C#:

(一)剖析经典的单件模式实现

  单件模式

  -- 确保一个类只有一个实例,并提供一个全局访问点

  -- 单件模式的类图可以说是所有模式的类图中最简单的

  -- 有一些对象其实我们只需一个,如线程池、缓存、对话框、处理偏好设置和注册表的对象、日志对象和充当打印机、显卡等设备的驱动程序的对象等。如果制造出多个实例,可能导致许多问题,如程序的行为异常、资源使用过度,或者结果不一致等

  1.新建一个控制台应用程序:SingletonPatternDemo。

  2.新建一个类:Singleton.cs

 namespace SingletonPatternDemo
{
public class Singleton
{
/// <summary>
/// 利用一个静态变量来记录Singleton类的唯一实例
/// </summary>
private static Singleton _uniqueInstance; //这里是其它变量... /// <summary>
/// 构造器私有化:只能在类内部才能调用构造器
/// </summary>
private Singleton() { } /// <summary>
/// 只能通过该方法获取到对象实例
/// </summary>
/// <returns></returns>
public static Singleton GetInstance()
{
//【注意】如果我们不需要该实例,它就永远不会产生。这就是“延迟实例化”(lazy instantiaze)
return _uniqueInstance ?? (_uniqueInstance = new Singleton()); #region 上行相当于以下代码
//if (_uniqueInstance == null)
//{
// _uniqueInstance = new Singleton();
//} //return _uniqueInstance;
#endregion
} //这里是其它方法...
}
}

  下面我们去掉注释看看

 namespace SingletonPatternDemo
{
public class Singleton
{
private static Singleton _uniqueInstance; private Singleton() { } public static Singleton GetInstance()
{
return _uniqueInstance ?? (_uniqueInstance = new Singleton());
}
}
}

  哇塞,这么简单啊!如果你也这么认为的话,那就错啦......接下来,我们看下第(二)部分

(二)场景应用

  巧克力工厂

  现代化的巧克力工厂具备计算机控制的巧克力锅炉,锅炉做的事,就是把巧克力和牛奶融在一起,然后送到下一个阶段,以制造成巧克力棒。

  这里有一个Choc-O-Holic公司的工业强度巧克力锅炉控制器,用于控制锅炉的日常运作,比如:锅炉内为空时才可以加入原料、锅炉内存在原料并且尚未煮沸时才能够进行煮沸,还有排出牛奶和巧克力的混合物时要求炉内存在已经煮沸的原料等。

  下列是巧克力锅炉控制器的代码:

 namespace SingletonPatternDemo
{
/// <summary>
/// 巧克力锅炉
/// </summary>
public class ChocolateBoiler
{
private bool Empty { get; set; }
private bool Boiled { get; set; } //代码开始时,锅炉为空,未燃烧
public ChocolateBoiler()
{
Empty = true;
Boiled = false;
} /// <summary>
/// 填充
/// </summary>
public void Fill()
{
//在锅炉内填入原料时,锅炉必须为空;
//填入原料后就把两个属性标识好
if (Empty)
{
//在锅炉内填满巧克力和牛奶的混合物... Empty = false;
Boiled = false;
}
} /// <summary>
/// 排出
/// </summary>
public void Drain()
{
//锅炉排出时,必须是满的,并且是煮过的;
//排出完毕后将Empty标志为true。
if (!Empty && Boiled)
{
//排出煮沸的巧克力和牛奶... Empty = true;
}
} /// <summary>
/// 煮沸
/// </summary>
public void Boil()
{
//煮混合物时,锅炉必须是满的,并且是没有煮过的;
//煮沸后,就把Boiled标识为true。
if (!Empty && !Boiled)
{
//将炉内物煮沸... Boiled = true;
}
}
}
}

试试根据(一)中所学的内容将它修改成单例模式

 namespace SingletonPatternDemo
{
/// <summary>
/// 巧克力锅炉
/// </summary>
public class ChocolateBoiler
{
private static ChocolateBoiler _uniqueInstance; //【新增】一个静态变量 private bool Empty { get; set; }
private bool Boiled { get; set; } //代码开始时,锅炉为空,未燃烧
private ChocolateBoiler() //【修改】原来是public
{
Empty = true;
Boiled = false;
} /// <summary>
/// 获取ChocolateBoiler对象实例
/// </summary>
/// <returns></returns>
public static ChocolateBoiler GetInstance() //【新增】一个静态方法
{
return _uniqueInstance ?? (_uniqueInstance = new ChocolateBoiler());
} /// <summary>
/// 填充
/// </summary>
public void Fill()
{
//在锅炉内填入原料时,锅炉必须为空;
//填入原料后就把两个属性标识好
if (Empty)
{
//在锅炉内填满巧克力和牛奶的混合物... Empty = false;
Boiled = false;
}
} /// <summary>
/// 排出
/// </summary>
public void Drain()
{
//锅炉排出时,必须是满的,并且是煮过的;
//排出完毕后将Empty标志为true。
if (!Empty && Boiled)
{
//排出煮沸的巧克力和牛奶... Empty = true;
}
} /// <summary>
/// 煮沸
/// </summary>
public void Boil()
{
//煮混合物时,锅炉必须是满的,并且是没有煮过的;
//煮沸后,就把Boiled标识为true。
if (!Empty && !Boiled)
{
//将炉内物煮沸... Boiled = true;
}
}
}
}

点击查看答案

【问题】万一同时存在多个ChocolateBoiler(巧克力锅炉),可能将发生很多糟糕的事情!... 敬请收看第(三)部分

(三)处理多线程

  现在,只要使用lock,就可以很简单地解决(二)中出现的问题了

 namespace SingletonPatternDemo
{
public class Singleton
{
/// <summary>
/// 利用一个静态变量来记录Singleton类的唯一实例
/// </summary>
private static Singleton _uniqueInstance; private static readonly object Locker = new object(); //这里是其它变量... /// <summary>
/// 构造器私有化:只能在类内部才能调用构造器
/// </summary>
private Singleton() { } /// <summary>
/// 只能通过该方法获取到对象实例
/// </summary>
/// <returns></returns>
public static Singleton GetInstance()
{
//lock:迫使每个线程在进入该方法之前,需要等候别的线程离开该方法,
// 也就是说,不会有两个线程可以同时进入该方法
lock (Locker)
{
if (_uniqueInstance == null)
{
//【注意】如果我们不需要该实例,它就永远不会产生。这就是“延迟实例化”(lazy instantiaze)
_uniqueInstance = new Singleton();
}
} return _uniqueInstance; } //这里是其它方法...
}
}

  但是,现在又出现了性能的问题!...

  方案一:使用“急切”创建实例,而不用延迟实例化的做法

 namespace SingletonPatternDemo
{
public class Singleton
{
//如果应用程序总是创建并使用单件实例,或者在创建和运行时方面的负担不太繁重,可以选择这种方法 //在静态初始化器中创建单件,这段代码保证了线程安全
private static readonly Singleton UniqueInstance = new Singleton(); private Singleton() { } public static Singleton GetInstance()
{
return UniqueInstance;
}
}
}

  方案二:用“双重检查加锁”

 namespace SingletonPatternDemo
{
public class Singleton
{
private static Singleton _uniqueInstance;
private static readonly object Locker = new object(); private Singleton() { } public static Singleton GetInstance()
{
//检查实例,如果不存在,就进入同步区块
if (_uniqueInstance == null)
{
lock (Locker)
{
if (_uniqueInstance == null)
{
//只有第一次才彻底执行这里的代码
_uniqueInstance = new Singleton();
}
}
} return _uniqueInstance;
} }
}

  完毕... ...

C#设计模式:单件(例)模式 -- 类也玩计划生育的更多相关文章

  1. java设计模式3--单例模式(Singleton)

    本文地址:http://www.cnblogs.com/archimedes/p/java-singleton-pattern.html,转载请注明源地址. 单例模式 保证一个类仅有一个实例,并提供一 ...

  2. 24种设计模式--多例模式【Multition Pattern】

    这种情况有没有?有!大点声,有没有?有,是,确实有,就出现在明朝,那三国期间的算不算,不算,各自称帝,各有各的地盘,国号不同.大家还 记得那首诗<石灰吟>吗?作者是谁?于谦,他是被谁杀死的 ...

  3. java设计模式——多例模式

    ★ 缓存在单例中的使用    缓存在编程中使用很频繁,有着非常重要的作用,它能够帮助程序实现以空间换取时间,通 常被设计成整个应用程序所共享的一个空间,现要求实现一个用缓存存放单例对象的类. 说明:该 ...

  4. 设计模式1---单例模式(Singleton pattern)

    单例模式Singleton 面试的时候,问到许多年轻的Android开发他所会的设计模式是什么,基本上都会提到单例模式,但是对 单例模式也是一知半解,在Android开发中我们经常会运用单例模式,所以 ...

  5. java设计模式1--单例模式

    1:单例模式简介 单例模式是一种常用的软件设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供唯一的实例.总而言之就是在系统中只会存在一个对象,其中的数据是共享的 特点: 单例类只能有一 ...

  6. JS设计模式1-单例模式

    单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如全局缓存,window对象.单例模式在js开发中单例模式的用途非常广泛,比如页面中有一个登录浮窗,无论单击多少次登录窗口,这个窗口只会创建一 ...

  7. [java]设计模式1-单例模式

    单例模式:单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管 ...

  8. javascript 设计模式1----单例模式

    定义:保证一个类仅有一个实例,并提供一个访问的全局接口: 就是收:当我们 var a = new a(); var a1 = new a()是:a与a1是相等的.怎么实现呢,就是第一次实例化.第二不在 ...

  9. 设计模式java----单例模式

    一.懒汉式单例 在第一次调用的时候实例化自己,Singleton的唯一实例只能通过getInstance()方法访问.线程不安全 /** * Created by Admin on 2017/3/19 ...

随机推荐

  1. 理解CSS外边距margin

    前面的话   margin是盒模型几个属性中一个非常特殊的属性.简单举几个例子:只有margin不显示当前元素背景,只有margin可以设置为负值,margin和宽高支持auto,以及margin具有 ...

  2. DailyTick 开发实录 —— 开始

    2009 年我读了李笑来老师的<把时间当朋友>,知识了柳比歇夫的时间记录法.当时激动坏了,马上动手实践起来.一开始的时候,是用一个小本子,走到哪儿都带着.完成一件事,就记录一下花费的时间. ...

  3. UITextView 输入字数限制

    本文介绍了UITextView对中英文还有iOS自带表情输入的字数限制,由于中文输入会有联想导致字数限制不准确所以苦恼好久,所以参考一些大神的博客终于搞定,欢迎大家参考和指正. 对于限制UITextV ...

  4. 运行执行sql文件脚本的例子

    sqlcmd -s -d db_test -r -i G:\test.sql 黑色字体为关键命令,其他颜色(从左至右):服务器名称,用户名,密码,数据库,文件路径 通过select @@servern ...

  5. Node.js:path、url、querystring模块

    Path模块 该模块提供了对文件或目录路径处理的方法,使用require('path')引用. 1.获取文件路径最后部分basename 使用basename(path[,ext])方法来获取路径的最 ...

  6. 基于AOP的MVC拦截异常让代码更优美

    与asp.net 打交道很多年,如今天微软的优秀框架越来越多,其中微软在基于mvc的思想架构,也推出了自己的一套asp.net mvc 框架,如果你亲身体验过它,会情不自禁的说‘漂亮’.回过头来,‘漂 ...

  7. CSS 3学习——transition 过渡

    以下内容根据官方规范翻译以及自己的理解整理. 1.介绍 这篇文档介绍能够实现隐式过渡的CSS新特性.文档中介绍的CSS新特性描述了CSS属性的值如何在给定的时间内平滑地从一个值变为另一个值. 2.过渡 ...

  8. EC笔记:第4部分:20、传递引用代替传值

    考虑以下场景: #include <iostream> #include <string> using namespace std; struct Person { strin ...

  9. SQL数据类型

    1.Character 字符串: 数据类型 描述 存储 char(n) 固定长度的字符串.最多8,000个字符. n varchar(n) 可变长度的字符串.最多8,000个字符.   varchar ...

  10. ORACLE从共享池删除指定SQL的执行计划

    Oracle 11g在DBMS_SHARED_POOL包中引入了一个名为PURGE的新存储过程,用于从对象库缓存中刷新特定对象,例如游标,包,序列,触发器等.也就是说可以删除.清理特定SQL的执行计划 ...