前言:
《GOF23种设计模式》是我持续性学习的一本书。由于一直处于穿插式学习。(数据结构,设计模式,Web开发)有点儿庞杂,一方面要学习,一方面还要完成本职工作。鉴于水平有限,只能这样了。
单例模式:
我个人理解为:在面向对象编程中,实现一个唯一的对象。
官方解释为:一个类只能有一个实例,并提供一个全局访问点。
public class Singleton
{
// 定义一个静态变量来保存类的实例
private static Singleton uniqueInstance;
// 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static Singleton GetInstance()
{
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
实际运用:
网上各种实例都是线程同步或者ADO.NET链接数据库的案例。都用烂了。我们今天利用另外一个案例。
案例:
我们在实际运用中,为了方便查找问题引入的一个概念:异常处理。
异常处理最基础的就是判断这一段代码的执行结果可能会遇到什么问题:比如装箱拆箱操作。
当我们捕获这个异常我们需要对它进行处理,我们是直接返回上一个栈还是在这里直接输出。
我们讨论的就是输出日志(Log)。查看Log是我们解决问题的根本,上面返回了各种异常信息和堆栈信息。
如何避免随意的打Log,这就是单例模式又一个经典案例。
思考这样一个问题,一个程序可以对应多少个日志文件?对于一个程序或者一个业务只需要一个日志文件,我们在设计Logger类的时候都是在构
造方法或初始化方法中生成日志文件的,也就是说,这基本上等价于一个Logger的实例对应一个新的日志文件(或重新对同一文件重新开启流)。
Logger myLogger = new Logger(@"D:\my.log");
如何才能够控制Log不被任意实例化,我们私有化构造函数,同时在Logger对象里利用静态变量实例化Logger。而为了给外部提供访问点,定义一个 公共方法GetInstance()
饿汉模式:
public class Logger
{
private static Logger instance = new Logger();
private Logger() { }
public static Logger GetInstance()
{
return instance;
}
}
以上就是单例模式的具体实现:参照上文的范式代码,于此对比参照。
懒汉模式:
private static Logger instance;
private Logger() { }
public static Logger GetInstance()
{
if (instance == null)
{
instance = new Logger();
}
return instance;
}
private static object initLockHelper = new object();
public static Logger GetInstance()
{
lock (initLockHelper)
{
if (instance == null)
{
instance = new Logger();
}
}
return instance;
}
但是,这个锁的目的是为了防止首次创建对象时发生的线程问题而增加的,对于之后的更多时间里,我们是不需要再进行加锁的,这个操作的资源消耗还是比较大的,因此,我们需要在lock之前先一次检查一下instance是否为null:
public static Logger GetInstance()
{
if (instance == null)
{
lock (initLockHelper)
{
if (instance == null)
{
instance = new Logger();
}
}
}
return instance;
}
这种锁机制我们称为双检锁机制,这样既保证了效率,又保证了线程安全。当我们的对象是一个轻量级类型时(类中没有太多的资源,比较简单)这是应该优先考虑使用饿汉模式,而对于类型复杂、资源占用较多的对象,可以考虑现用现加载,即懒汉模式。