跟我一起学23种经典设计模式——单例模式
让我们一起开启设计模式吧!笔者以后会不定时更新我学习设计模式的随笔,一些重要的要点我都直接写在代码的注释里,好了,废话不多说,让我们从单例模式开始吧!
一、单线程下实例唯一
namespace SingletonPattern
{
/// <summary>
/// 这种的单例模式只能保证在单线程内实例唯一
/// </summary>
public class SingletonOnlyInOneThread
{
private static SingletonOnlyInOneThread _instance;
private SingletonOnlyInOneThread() { }
public static SingletonOnlyInOneThread Instance//这里作为一个属性来获取
{
get
{
if (_instance == null)
{
_instance = new SingletonOnlyInOneThread();
}
return _instance;
}
}
}
}
{
/// <summary>
/// 这种的单例模式只能保证在单线程内实例唯一
/// </summary>
public class SingletonOnlyInOneThread
{
private static SingletonOnlyInOneThread _instance;
private SingletonOnlyInOneThread() { }
public static SingletonOnlyInOneThread Instance//这里作为一个属性来获取
{
get
{
if (_instance == null)
{
_instance = new SingletonOnlyInOneThread();
}
return _instance;
}
}
}
}
二、多线程下实例唯一
namespace SingletonPattern
{
/// <summary>
/// 在多线程内保证实例唯一
/// </summary>
public class SingletonInMultiThread
{
private static volatile SingletonInMultiThread _instance;//volatile关键字保证实例在多个线程中同步,即在一个线程内对象内部发生了变化,其它线程内的对象也发生相应的变化
private static object objectHelper = new object();//帮助对象,用于lock语句
private SingletonInMultiThread() { }
public SingletonInMultiThread Instance
{
get
{
if(_instance ==null)
{
lock (objectHelper )//lock关键字使得同一时间内只能有一个线程进入语句块,其它线程必须等待
{
if (_instance == null)//这里使用的double check来确保在进入lock语句块后还未实例化对象
{
_instance = new SingletonInMultiThread();
}
}
}
return _instance;
}
}
}
}
{
/// <summary>
/// 在多线程内保证实例唯一
/// </summary>
public class SingletonInMultiThread
{
private static volatile SingletonInMultiThread _instance;//volatile关键字保证实例在多个线程中同步,即在一个线程内对象内部发生了变化,其它线程内的对象也发生相应的变化
private static object objectHelper = new object();//帮助对象,用于lock语句
private SingletonInMultiThread() { }
public SingletonInMultiThread Instance
{
get
{
if(_instance ==null)
{
lock (objectHelper )//lock关键字使得同一时间内只能有一个线程进入语句块,其它线程必须等待
{
if (_instance == null)//这里使用的double check来确保在进入lock语句块后还未实例化对象
{
_instance = new SingletonInMultiThread();
}
}
}
return _instance;
}
}
}
}
三、实现多线程下实例唯一的简单方式
namespace SingletonPattern
{
/// <summary>
///保证实例在多线程内唯一的一种简单实现方式
/// </summary>
public sealed class SingletonInMultiThreadWithEasyWay
{
public static readonly SingletonInMultiThreadWithEasyWay Instance = new SingletonInMultiThreadWithEasyWay();
private SingletonInMultiThreadWithEasyWay() { }
}
{
/// <summary>
///保证实例在多线程内唯一的一种简单实现方式
/// </summary>
public sealed class SingletonInMultiThreadWithEasyWay
{
public static readonly SingletonInMultiThreadWithEasyWay Instance = new SingletonInMultiThreadWithEasyWay();
private SingletonInMultiThreadWithEasyWay() { }
}
}
用reflector反编译后变成:
public sealed class SingletonInMultiThreadWithEasyWayCompile
{
public static readonly SingletonInMultiThreadWithEasyWayCompile Instance;
static SingletonInMultiThreadWithEasyWayCompile ()//一个静态的构造函数
{
Instance = new SingletonInMultiThreadWithEasyWayCompile();
}
private SingletonInMultiThreadWithEasyWayCompile() { }
}
{
public static readonly SingletonInMultiThreadWithEasyWayCompile Instance;
static SingletonInMultiThreadWithEasyWayCompile ()//一个静态的构造函数
{
Instance = new SingletonInMultiThreadWithEasyWayCompile();
}
private SingletonInMultiThreadWithEasyWayCompile() { }
}
这样的实现可以自动帮我们加锁实现多线程实例唯一,
但如果我们如果以这种实现的话,这样会带来的一个问题就是无法实现有参构造函数的单例,因为静态构造函数不允许带参数,解决方法:使用属性或方法在得到实例后进行初始化对象,比如:
public sealed class SingletonInMultiThreadWithEasyWayCompile
{
public static readonly SingletonInMultiThreadWithEasyWayCompile Instance;
static SingletonInMultiThreadWithEasyWayCompile ()//一个静态的构造函数
{
Instance = new SingletonInMultiThreadWithEasyWayCompile();
}
private SingletonInMultiThreadWithEasyWayCompile() { }
{
public static readonly SingletonInMultiThreadWithEasyWayCompile Instance;
static SingletonInMultiThreadWithEasyWayCompile ()//一个静态的构造函数
{
Instance = new SingletonInMultiThreadWithEasyWayCompile();
}
private SingletonInMultiThreadWithEasyWayCompile() { }
public int Property1 { get; set; }
public int Property2 { get; set; }
public void Init(int property1, int property2)
{
this.Property1 = property1;
this.Property2 = property2;
}
}
public int Property2 { get; set; }
public void Init(int property1, int property2)
{
this.Property1 = property1;
this.Property2 = property2;
}
}