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 ...
随机推荐
- Spring基于AOP的事务管理
Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...
- SQL:指定名称查不到数据的衍伸~空格 换行符 回车符的批量处理
异常处理汇总-数据库系列 http://www.cnblogs.com/dunitian/p/4522990.html 先看看啥情况 复制查询到的数据,粘贴一下看看啥情况 那就批量处理一下~ 就这样 ...
- Redis链表实现
链表在 Redis 中的应用非常广泛, 比如列表键的底层实现之一就是链表: 当一个列表键包含了数量比较多的元素, 又或者列表中包含的元素都是比较长的字符串时, Redis 就会使用链表作为列表键的底层 ...
- 最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)
在项目开发中,除了对数据的展示更多的就是对文件的相关操作,例如文件的创建和删除,以及文件的压缩和解压.文件压缩的好处有很多,主要就是在文件传输的方面,文件压缩的好处就不需要赘述,因为无论是开发者,还是 ...
- 前端自动化构建工具gulp记录
一.安装 1)安装nodejs 通过nodejs的npm安装gulp,插件也可以通过npm安装.windows系统是个.msi工具,只要一直下一步即可,软件会自动在写入环境变量中,这样就能在cmd命令 ...
- Asp.Net Core + Dapper + Repository 模式 + TDD 学习笔记
0x00 前言 之前一直使用的是 EF ,做了一个简单的小项目后发现 EF 的表现并不是很好,就比如联表查询,因为现在的 EF Core 也没有啥好用的分析工具,所以也不知道该怎么写 Linq 生成出 ...
- Android 微信第三方登录(个人笔记)
今天在写微信登录,花了半天时间搞定.然后写下自己的笔记,希望帮助更多的人...欢迎各位指教. 微信授权登录,官方说的不是很清楚.所以导致有一部分的坑. 微信注册应用平台的应用签名,下载 微信签名生成工 ...
- ViewController respondsToSelector 错误的解决方法
原因解析:(来自别人博客分析)某个公共类或系统提供的控件,存在delegate方法,当创建此公共控件的容器类已经销毁,而这个控件对应的服务是在其它run loop中进行的,控件销毁或者需要进行状态通知 ...
- 敏捷转型历程 - Sprint3 回顾会
我: Tech Leader 团队:团队成员分布在两个城市,我所在的城市包括我有4个成员,另外一个城市包括SM有7个成员.另外由于我们的BA离职了,我暂代IT 的PO 职位.PM和我在一个城市,但他不 ...
- 数据库备份并分离日志表(按月)sh 脚本
#!/bin/sh year=`date +%Y` month=`date +%m` day=`date +%d` hour=`date +%H` dir="/data/dbbackup/f ...