一、简介
什么是单例模式?
单例可以理解为一个类只有一个实例,因此单例模式就是为了保证这个类只会有一个实例而总结的一种方法。
它在什么情况下使用的?
从单例模式的定义中我们可以看出——单例模式的使用自然是当我们的系统中某个对象只需要一个实例的情况,例如:操作系统中只能有一个任务管理器,操作文件时,同一时间内只允许一个实例对其操作等。
二、原理
由此,单例模式有两个关键点:
- 1)确保一个类只有一个实例;
- 2)提供一个访问它的全局访问点;
2.1 单一实例
通常实例是在调用类时,new出来的。但是为了保证一个类只有一个实例,因此实例的创建应该是:
- 1、静态的:每个线程都有自己的线程栈,定义为静态主要是为了在多线程确保类有一个实例;
- 2、在类的内部创建;
- 3、构造函数设置为私有的;
- 4、对于多线程,需要加锁;
2.2 全局访问点
因为实例在类内部创建,构造函数还是私有的,所以需要一个方法/属性来允许外部获取这个实例。这个方法特点是:
* 1、public
* 2、无需实例即可调用,即static的方法
* 3、返回值是内部实例
三、实现
GitHub版:1单例模式.cs
原理版:
/// <summary>
/// 单线程版单例模式
/// </summary>
public class Singleton_0
{
// 定义一个静态变量来保存类的实例
private static Singleton_0 uniqueInstance;
// 定义私有构造函数,使外界不能创建该类实例
private Singleton_0()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static Singleton_0 GetInstance()
{
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new Singleton_0();
}
return uniqueInstance;
}
}
多线程版本,就是多加了一个锁:
/// <summary>
/// 多线程下单例模式的实现
/// </summary>
public class Singleton_t
{
// 定义一个静态变量来保存类的实例
private static Singleton_t uniqueInstance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private Singleton_t()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static Singleton_t GetInstance()
{
// 当第一个线程运行到这里时,此时会对locker对象 "加锁",
// 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
// lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
// 双重锁定只需要一句判断就可以了
if (uniqueInstance == null)
{
lock (locker)
{
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new Singleton_t();
}
}
}
return uniqueInstance;
}
#region 数据
public int data = 0;
public string strData = "0";
#endregion
}
四、测试
简单运行测试一下:
调用的委托和包含了这个单例的类
delegate void show(string data);
public void showTextbox(string data)
{
textBox1.Text += data + Environment.NewLine;
}
private class TestModel
{
public Singleton_t m_test = null;
public void Initializer()
{
m_test = Singleton_t.GetInstance();
}
}
button事件
private void button1_Click(object sender, EventArgs e)
{
var test1 = Singleton_t.GetInstance();
Invoke(new show(showTextbox), new object[] { "初始值:"+test1.strData });
test1.data = 1;
test1.strData = "1";
Invoke(new show(showTextbox), new object[] { "赋值后:"+test1.strData });
var test2 = Singleton_t.GetInstance();
Invoke(new show(showTextbox), new object[] { "获取的第二个实例值:"+test2.strData });
TestModel test3 = new TestModel();
test3.Initializer();
Invoke(new show(showTextbox), new object[] { "在另一个类中的作为成员变量时:" + test3.m_test.strData });
test1.strData = "3";
Invoke(new show(showTextbox), new object[] { "所有实例同步变化:" + test3.m_test.strData });
}
结果:
初始值:0
赋值后:1
获取的第二个实例值:1
在另一个类中的作为成员变量时:1
所有实例同步变化:3
总结
单例模型还是比较简单的