C#设计模式之单例模式实例讲解
前言
最近开始花点心思研究下设计模式,主要还是让自己写的代码可重用性高、保证代码可靠性。所谓设计模式,我找了下定义:是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
为什么要提倡“Design Pattern(设计模式)”?
根本原因是为了代码复用,增加可维护性。因此这次我们来学习下设计模式,最后会通过C#语言来实现这些设计模式作为例子,深刻理解其中的精髓。
定义
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
特点
1、 某个类只能有一个实例
2、它必须自行创建这个实例
3、它必须自行向整个系统提供这个实例。
优缺点
优点:
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
缺点:
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。
/// <summary>
/// 单例模式
/// </summary>
public class Singleton
{
// 定义一个静态变量来保存类的实例
private static Singleton mySingleton;
// 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{
}
//定义公有方法提供一个全局访问点。
public static Singleton GetInstance()
{
//这里的lock其实使用的原理可以用一个词语来概括“互斥”这个概念也是操作系统的精髓
//其实就是当一个进程进来访问的时候,其他进程便先挂起状态
if (mySingleton == null)
{
mySingleton = new Singleton();
}
return mySingleton;
}
}
上面的单例模式的实现是有问题的,当多个用户或者方法同时访问的时候,便会出现多个用户同时拿到了mySingleton==null的结果,这个明显不是我们想要的,因此,我们应该通过一个锁来互斥这个方法,当很多线程同时访问的时候,只允许一个线程进入到代码中执行,而其他的便只能处于挂起的状态。
/// <summary>
/// 单例模式
/// </summary>
public class Singleton
{
// 定义一个静态变量来保存类的实例
private static Singleton mySingleton;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{
}
//定义公有方法提供一个全局访问点。
public static Singleton GetInstance()
{
//这里的lock其实使用的原理可以用一个词语来概括“互斥”这个概念也是操作系统的精髓
//其实就是当一个进程进来访问的时候,其他进程便先挂起状态
if (mySingleton == null)//区别就在这里
{
lock (locker)
{
// 如果类的实例不存在则创建,否则直接返回
if (mySingleton == null)
{
mySingleton = new Singleton();
}
}
}
return mySingleton;
}
}
其实在一些项目中,单例模式早就有了体现。在开发asp.net的项目中,就已经用这种方法来包装http上下文来实现计算机资源的节省。
/// <summary>
/// 业务仓储
/// </summary>
public IBLL.IBLLSession BLLSession;
//---------------------定义上下文属性
#region 实例构造函数 初始化业务仓储 + OperateContext()
public OperateContext()
{
BLLSession = DI.SpringHelper.GetObject<IBLL.IBLLSession>("BLLSession");
}
#endregion
#region Http上下文 以及相关属性
/// <summary>
/// Http上下文
/// </summary>
HttpContext ContextHttp
{
get
{
return HttpContext.Current;
}
}
HttpResponse Response
{
get
{
return ContextHttp.Response;
}
}
HttpRequest Request
{
get
{
return ContextHttp.Request;
}
}
HttpSessionState Session
{
get
{
return ContextHttp.Session;
}
}
#endregion
#region 获取当前操作上下文(存在线程中,提高效率) + OperateContext Current
// <summary>
/// 获取当前操作上下文(存在线程中,提高效率)
/// </summary>
public static OperateContext Current
{
get
{
OperateContext o = CallContext.GetData(typeof(OperateContext).Name) as OperateContext;
if (o == null)
{
o = new OperateContext();
CallContext.SetData(typeof(OperateContext).Name, o);
}
return o;
}
}
#endregion
总结
到这里,就和大家一起先了解了单例模式到底是个什么东西,其实在一些项目中,这种模式就已经应用了,只是我们没有去发现和总结,不过本来设计模式就是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。哎。。。。这次是第二次编辑了,本来这个单例模式已经发布了好多天,竟然被我新的一篇观察者模式给覆盖了,数据取不回来,只能匆匆完稿,大家见谅啊,有问题我们一起来讨论,毕竟我也是初学者。