C#设计模式:单件(例)模式 -- 类也玩计划生育
这里写的代码,相当于《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#设计模式:单件(例)模式 -- 类也玩计划生育的更多相关文章
- java设计模式3--单例模式(Singleton)
本文地址:http://www.cnblogs.com/archimedes/p/java-singleton-pattern.html,转载请注明源地址. 单例模式 保证一个类仅有一个实例,并提供一 ...
- 24种设计模式--多例模式【Multition Pattern】
这种情况有没有?有!大点声,有没有?有,是,确实有,就出现在明朝,那三国期间的算不算,不算,各自称帝,各有各的地盘,国号不同.大家还 记得那首诗<石灰吟>吗?作者是谁?于谦,他是被谁杀死的 ...
- java设计模式——多例模式
★ 缓存在单例中的使用 缓存在编程中使用很频繁,有着非常重要的作用,它能够帮助程序实现以空间换取时间,通 常被设计成整个应用程序所共享的一个空间,现要求实现一个用缓存存放单例对象的类. 说明:该 ...
- 设计模式1---单例模式(Singleton pattern)
单例模式Singleton 面试的时候,问到许多年轻的Android开发他所会的设计模式是什么,基本上都会提到单例模式,但是对 单例模式也是一知半解,在Android开发中我们经常会运用单例模式,所以 ...
- java设计模式1--单例模式
1:单例模式简介 单例模式是一种常用的软件设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供唯一的实例.总而言之就是在系统中只会存在一个对象,其中的数据是共享的 特点: 单例类只能有一 ...
- JS设计模式1-单例模式
单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如全局缓存,window对象.单例模式在js开发中单例模式的用途非常广泛,比如页面中有一个登录浮窗,无论单击多少次登录窗口,这个窗口只会创建一 ...
- [java]设计模式1-单例模式
单例模式:单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管 ...
- javascript 设计模式1----单例模式
定义:保证一个类仅有一个实例,并提供一个访问的全局接口: 就是收:当我们 var a = new a(); var a1 = new a()是:a与a1是相等的.怎么实现呢,就是第一次实例化.第二不在 ...
- 设计模式java----单例模式
一.懒汉式单例 在第一次调用的时候实例化自己,Singleton的唯一实例只能通过getInstance()方法访问.线程不安全 /** * Created by Admin on 2017/3/19 ...
随机推荐
- 【.net 深呼吸】序列化中的“引用保留”
假设 K 类中有两个属性/字段的类型相同,并且它们引用的是同一个对象实例,在序列化的默认处理中,会为每个引用单独生成数据. 看看下面两个类. [DataContract] public class 帅 ...
- 一个免费的、跨平台的、开源音频编辑器Audacity
Audacity 是一个免费的开源程序,用于编辑音频录制.它可在多个平台(windows/linux)上运行.Audacity 基于 GUI,是一个具有多种选项的强大程序.它支持您录制各种类型的声音. ...
- java字符乱码
在java中处理字符时,经常会发生乱码,而主要出现的地方在读取文本文件时发生,或者是写入到文件中,在其他地方打开乱码. 如下例子: BufferedReader br = null; try { br ...
- html与html5
HTML 是一种在 Web 上使用的通用标记语言.HTML 允许你格式化文本,添加图片,创建链接.输入表单.框架和表格等等,并可将之存为文本文件,浏览器即可读取和显示.HTML 的关键是标签,其作用是 ...
- 《Django By Example》第二章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:翻译完第一章后,发现翻译第二章的速 ...
- Carousel 旋转画廊特效的疑难杂症
疑难杂症 该画廊特效的特点就是前后元素有层级关系. 我想很多人应该看过或者用过这个插件carousel.js,网上也有相关的教程.不知道这个插件的原型是哪个,有知道的朋友可以告诉我. 该插件相对完美, ...
- app引导页(背景图片切换加各个页面动画效果)
前言:不知不觉中又加班到了10点半,整个启动页面做了一天多的时间,一共有三个页面,每个页面都有动画效果,动画效果调试起来麻烦,既要跟ios统一,又要匹配各种不同的手机,然后产品经理还有可能在中途改需求 ...
- MySQL加密
MySQL字段加密和解密 1.加密:aes_encrypt('admin','key') 解密:aes_decrypt(password,'key') 2.双向加密 通过密钥去加密,解密的时候的只有知 ...
- 【译】Meteor 新手教程:在排行榜上添加新特性
原文:http://danneu.com/posts/6-meteor-tutorial-for-fellow-noobs-adding-features-to-the-leaderboard-dem ...
- [httpserver]如何解析HTTP请求报文
这个http server的实现源代码我放在了我的github上,有兴趣的话可以点击查看哦. 在上一篇文章中,讲述了如何编写一个最简单的server,但该程序只是接受到请求之后马上返回响应,实在不能更 ...