昨天给大家介绍了原型模式,今天给大家介绍的是单例模式,也是最简单的一种创建型模式。
在我们的软件系统中,有时候保持一个类只有一个实例是非常重要的。比如说,操作系统中的任务管理器,只能有一个窗口,也就是说它在系统中只能有一个实例,否则就会弹出多个任务管理器窗口。再比如说,系统中的打印机,同一时间只能执行一个打印任务,如果有多个打印机实例,那么同一时间可以打印多个任务,这会导致打印结果发生混乱。因此,软件开发中,有时候保持一个类只有一个实例是非常重要的。
先看单例模式的定义:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。
那么如何确保一个类只有一个实例并且可以被外部访问呢?从定义上看有三点:一是一个类只能有一个实例,而是它必须自己创建这个实例(这样可以防止外部对它实例化),三是它必须提供一个全局的访问点(静态全局变量)。
单例模式的角色非常简单,只有一个单例类
那么该如何实现单例模式呢?请看下面的代码
namespace 单例模式
{
public class Singleton
{
//第二步:提供一个全局访问点,外部通过这个访问点访问实例
private static Singleton instance = null;
//第一步:将构造函数声明为Private,可以防止外部对该对象进行实例化
private Singleton() { }
//第三步:单例类本身负责创建实例
public static Singleton GetInstance()
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
}
namespace 单例模式
{
class Program
{
static void Main(string[] args)
{
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if (s1 == s2)
{
Console.Write("s1和s2是同一个实例!");
}
else
{
Console.Write("s1和s2不是同一个实例!");
}
Console.ReadLine();
}
}
}
代码中单例模式的实现步骤已经写得很清楚,这里就不在作解释了。下面看看运行结果
运行结果显示s1和s2是同一个实例,说明外部对象拿到的是Singleton的同一个实例。
上面的实现方法是单例模式最简单的实现方法。
接下来来介绍两种不同实现方法的单例模式,饿汉式单例和懒汉式单例。
先来看看饿汉式单例类的代码。
namespace 单例模式
{
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton() { }
public static Singleton GetInstance()
{
return instance;
}
}
}
当类被加载的时候,静态变量instance就会被初始化,然后创建单例类的实例。
然后我们来看看懒汉式单例模式的代码,懒汉式和饿汉式的构造函数都是私有的,不同的是懒汉式单例类不会在类加载时初始化单例类,而是在调用静态工厂方法的时候实例化单例类。来看看下面的代码。
public class Singleton
{
private static Singleton instance = null;
private static readonly object lockObject = new object();
private Singleton() { }
public static Singleton GetInstance()
{
//第一次判断
if (instance == null)
{
//加锁,防止同一时刻多个线程同时访问,导致实例化多个对象
lock (lockObject)
{
//第二次判断
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
在代码中使用了Lock关键字对指定代码片段上锁,防止同一时刻多个线程同时访问单例类,最后导致系统的实例不是一个,而是多个。
代码中两次判断instance==null,是必不可少的。假如说两个线程同时通过第一次判断,第一个线程进入lock代码片段后,判断instance还是为空,就实例化。如果第二个线程进来我们不判断的话,它还会继续实例化单例类。
下一篇文章将给大家介绍创建型模式中的最后一种—-建造者模式。