C#设计模式应用-单件模式(Singleton Pattern)
C#设计模式应用-单件模式(Singleton Pattern)
//如果两个线程同时访问_Instance静态变量,此时if逻辑运算结果=True(因为_Instance还没有实例化).因此会创建两次实例。
//尽管发生的概率较低,先预防和了理原理是需要的。
if (_Instance == null) _Instance = new SingletonII();
关键的部分就是lock(_lock)方法,因为不管几个线程同时访问它,只能有一个线程进入并执行其中的代码,也就是去创建单件类的实例,当一个线程创建了单件类的实例后下一个线程再去判断if (_Instance == null)时,_Instance变量不再为null,所以也就不会有新的实例被创建了,这种写法网友称之为“双重检查”。
测试类,用于测试上面几种单件模式
测试:
扫一扫加微信
一、什么是单件模式(Singleton Pattern)
单件模式是一种用于确保整个应用程序中只有一个类实例且这个实例所占资源在整个应用程序中是共享时的程序设计方法。
二、单件模式结构
单件模式的结构非常简单,包括防止其他对象创建实例的私有构造函数、保存惟一实例的私有变量和全局访问接口等。
三、单件模式使用场合
当需要频繁创建一个类的实例时且该类只有固定业务逻辑。比如系统参数对象,通常我们会定义一个SystemSettings类。而该类在整个程序的生命周期内使用,我们可以通过这种方式读取系统参数:
//获取SQL连接字符串
string conn = SystemSettings.Default.SqlConnection;
......
string conn = SystemSettings.Default.SqlConnection;
......
SystemSettins.Default是单件实例,在整个生命周期只实例化一次。
在任何窗体或类使用下面代码虽然达到同样目的但是写法低劣:
//获取SQL连接字符串
string conn = new SystemSettins().SqlConnection; //每次创建新实例
string conn = new SystemSettins().SqlConnection; //每次创建新实例
四、单件模式创建单件实例的两种方法
●初始化静态成员时实例化对象
//单件模式实现方式1
public sealed class Singleton
{
//私有构造器,外部不能实例化这个类
private Singleton() { }
//创建静态实例.初始化静态成员时实例化对象,速度最快!
private static Singleton _Instance = new Singleton();
//单件模式实例
public static Singleton Instance
{
get { return _Instance; }
}
public void MyMothod()
{
Console.WriteLine("正在调用单件模式的方法!");
Console.ReadKey();
}
}
public sealed class Singleton
{
//私有构造器,外部不能实例化这个类
private Singleton() { }
//创建静态实例.初始化静态成员时实例化对象,速度最快!
private static Singleton _Instance = new Singleton();
//单件模式实例
public static Singleton Instance
{
get { return _Instance; }
}
public void MyMothod()
{
Console.WriteLine("正在调用单件模式的方法!");
Console.ReadKey();
}
}
将类声明为sealed是防止类被派生,将构造函数声明为私有(private)是防止外部直接创建对象。Singleton类只提供Instance属性访问实例,这种方式将类封装更严密。
●在使用时实例化对象
//单件模式实现方式2
public sealed class SingletonII
{
//私有构造器,外部不能实例化这个类
private SingletonII() { }
//声明静态变量
private static SingletonII _Instance = null;
//
//单件模式实例II,在使用时才创建实例。
//通常在占用内存超大的类才适用这种方法。
public static SingletonII Instance
{
get
{
//在使用时才创建单件实例,速度较第一种方式略慢,但基于现在xx86机器,速度问题直接忽略!
if (_Instance == null) _Instance = new SingletonII();
return _Instance;
}
}
public void MyMothod()
{
Console.WriteLine("正在调用单件模式II的方法!");
Console.ReadKey();
}
}
public sealed class SingletonII
{
//私有构造器,外部不能实例化这个类
private SingletonII() { }
//声明静态变量
private static SingletonII _Instance = null;
//
//单件模式实例II,在使用时才创建实例。
//通常在占用内存超大的类才适用这种方法。
public static SingletonII Instance
{
get
{
//在使用时才创建单件实例,速度较第一种方式略慢,但基于现在xx86机器,速度问题直接忽略!
if (_Instance == null) _Instance = new SingletonII();
return _Instance;
}
}
public void MyMothod()
{
Console.WriteLine("正在调用单件模式II的方法!");
Console.ReadKey();
}
}
五、多线程情况下使用单件模式
以上讨论的单件模式可以在单线程环境中使用,如果是在多线程环境中,上面的代码就有问题,请看下面的代码注释:
//如果两个线程同时访问_Instance静态变量,此时if逻辑运算结果=True(因为_Instance还没有实例化).因此会创建两次实例。
//尽管发生的概率较低,先预防和了理原理是需要的。
if (_Instance == null) _Instance = new SingletonII();
解决此问题需要将对象加锁:
//单件模式实现方式3,多线程访问情况下创建单件实例
public sealed class SingletonIII
{
//私有构造器,外部不能实例化这个类
private SingletonIII() { }
//用于加锁的对象,是个临时对象,除了用于加锁无其它意义.
private static readonly object _lock = new object();
//声明静态变量
private static SingletonIII _Instance = null;
//单件模式实例III,多线程访问情况下处理
public static SingletonIII Instance
{
get
{
lock (_lock)//加锁,现在只能一个线程访问
{
//在使用时才创建单件实例
if (_Instance == null) _Instance = new SingletonIII();
return _Instance;
}
}
}
public void MyMothod()
{
Console.WriteLine("正在调用单件模式III的方法!");
Console.ReadKey();
}
}
public sealed class SingletonIII
{
//私有构造器,外部不能实例化这个类
private SingletonIII() { }
//用于加锁的对象,是个临时对象,除了用于加锁无其它意义.
private static readonly object _lock = new object();
//声明静态变量
private static SingletonIII _Instance = null;
//单件模式实例III,多线程访问情况下处理
public static SingletonIII Instance
{
get
{
lock (_lock)//加锁,现在只能一个线程访问
{
//在使用时才创建单件实例
if (_Instance == null) _Instance = new SingletonIII();
return _Instance;
}
}
}
public void MyMothod()
{
Console.WriteLine("正在调用单件模式III的方法!");
Console.ReadKey();
}
}
关键的部分就是lock(_lock)方法,因为不管几个线程同时访问它,只能有一个线程进入并执行其中的代码,也就是去创建单件类的实例,当一个线程创建了单件类的实例后下一个线程再去判断if (_Instance == null)时,_Instance变量不再为null,所以也就不会有新的实例被创建了,这种写法网友称之为“双重检查”。
测试类,用于测试上面几种单件模式
public class Tester2
{
//测试单件模式实现方式1- 初始化静态成员时实例化对象
public static void Test()
{
Singleton.Instance.MyMothod();
}
//测试单件模式实现方式2-在使用时才创建实例
public static void Test1()
{
SingletonII.Instance.MyMothod();
}
//测试单件模式实现方式3-多线程访问情况下创建单件实例
public static void Test2()
{
SingletonIII.Instance.MyMothod();
}
}
{
//测试单件模式实现方式1- 初始化静态成员时实例化对象
public static void Test()
{
Singleton.Instance.MyMothod();
}
//测试单件模式实现方式2-在使用时才创建实例
public static void Test1()
{
SingletonII.Instance.MyMothod();
}
//测试单件模式实现方式3-多线程访问情况下创建单件实例
public static void Test2()
{
SingletonIII.Instance.MyMothod();
}
}
测试:
class Program
{
static void Main(string[] args)
{
Tester2.Test();
Tester2.Test1();
Tester2.Test2();
}
}
{
static void Main(string[] args)
{
Tester2.Test();
Tester2.Test1();
Tester2.Test2();
}
}
扫一扫加微信
版权声明:本文为开发框架文库发布内容,转载请附上原文出处连接
NewDoc C/S框架网