【题外话】
最近整理博客,虽然文章不多,但是文章命名和文章分类好像也整的很混乱- -。之后会本着标题命名便于检索、文章分类依据文章所涉及知识概念的原则进行划分。
【单例概述】
定义:单例,顾名思义,单个实例,即应用单例模式的类有且只有一个实例对象,并提供一个全局访问点来共其他类与对象访问。
(1)有且只有一个实例对象。
有实例对象说明该类不是抽象类;只有一个实例对象表示不能随时随地的new一个该类的对象出来(这不是对开发者的约定,而是代码层面上的约定,即如果你这样做了,编辑器会提示你错误),即该类的构造函数是private级别,只能在类的内部构建实例对象;
(2)提供全局访问点使其他类与对象访问。
这说明应用单例模式的类在提供实例访问方法时,该方法应该是静态的。
有了如上的分析,就可以很轻松的创建单例类了,代码并不是很复杂。为什么要分成“C#中的单例模式”和“Unity中的伪单例模式”,前者指C#语言本身,后者指在Unity的Mono框架下。还有一点要说的,下面所有所有的例子都只是说明单例如何创建,不是说类中就这么点东西。。。- -
【C#中的单例模式】
在单例模式中,根据应用情况的不同,也有着不同的实现方式。先把统一的访问方式写出来,这种访问方式应用于该命题下述的所有模式。
namespace CSharpTest
{
class Program
{
static void Main(string[] args)
{
Singleton s = Singleton.GetInstance();
}
}
}
饿汉模式
意思是,在该类装载时构建类的单例。(类的装载可以粗浅的理解为发生在程序启动时,Main之前)也就是说,这个单例跟你什么时候用,是否要用无关,只要运行程序,这个单例就存在了。这样做的坏处是如果程序初始化时要载入的资源过多时显然这种方式又提高了加载的负担,其次如果没有使用到的话也浪费了内存。
namespace CSharpTest
{
public class Singleton
{
//私有化构造函数 使得外部无法构造类的实例
private Singleton() { }
//定义实例对象时便创建实例
private static Singleton _instance = new Singleton();
//提供全局访问点
public static Singleton GetInstance()
{
return _instance;
}
}
}
懒汉模式
意思是,在该类的单例被使用时构造类的单例。它相比饿汉模式更加灵活,所以应用更为广泛。
基本模式(单线程模式)
在单线程中,只需做如下定义:
namespace CSharpTest
{
public class Singleton
{
//私有化构造函数 使得外部无法构造类的实例
private Singleton() { }
//定义一个空的单例对象
private static Singleton _instance;
//提供全局访问点
public static Singleton GetInstance()
{
//第一次访问时会创建实例
if (_instance == null)
_instance = new Singleton();
return _instance;
}
}
}
多线程模式
在多线程的程序中,构造单例的方式要发生什么变化呢?我们来依据单线程模式构造单例的代码来分析:全局访问方法内提供了如下的判断条件:
if (_instance == null)
_instance = new Singleton();
这会引发什么问题?以两个线程情况为例。当两个线程运行到这里时,可能线程1刚经过判断还没创建实例时,线程2就也已经通过判断要创建实例了,这会造成两个线程都创建了实例,这就违背了我们单例模式的初衷。所以我们要对其进行“加锁”,进行争用条件判断。即谁先来的谁先访问,我访问的时候你不许访问,我访问完了你再访问。
实现思路如下:
这里使用一个辅助对象(必须是引用类型)充当锁ÿ