单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。
使用场景
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
单例模式结构图
懒汉式单例类
懒汉式单例类,即要在第一次被引用时,才会将自己实例化。
比如,在主窗体上不同的2个按钮打开同一个工具窗口。
工具窗口类:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConsoleApp2
{
public partial class FormToolbox : Form
{
private static FormToolbox ftb = null;
//构造方法私有,外部代码不能直接new来实例化它
private FormToolbox()
{
InitializeComponent();
}
public static FormToolbox GetInstance()
{
if (ftb == null || ftb.IsDisposed)
{
ftb = new FormToolbox();
ftb.MdiParent = Form1.ActiveForm;
}
return ftb;
}
private void FormToolbox_Load(object sender, EventArgs e)
{
}
}
}
主窗口类:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConsoleApp2
{
public partial class Form1 : Form
{
FormToolbox formToolbox;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.IsMdiContainer = true;
}
private void ToolStripMenuItem_Click(object sender, EventArgs e)
{
FormToolbox.GetInstance().Show();
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
FormToolbox.GetInstance().Show();
}
}
}
多线程时的单例
防止多线程程序中,多线程同时访问FormToolbox类,调用GetInstance()方法,会造成创建多个实例的情况。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConsoleApp2
{
public partial class FormToolbox : Form
{
private static FormToolbox ftb = null;
//程序运行时创建一个静态只读的进程辅助对象
private static readonly object syncRoot = new object();
private FormToolbox()
{
InitializeComponent();
}
public static FormToolbox GetInstance()
{
lock (syncRoot)//加锁
{
if (ftb == null || ftb.IsDisposed)
{
ftb = new FormToolbox();
ftb.MdiParent = Form1.ActiveForm;
}
}
return ftb;
}
private void FormToolbox_Load(object sender, EventArgs e)
{
}
}
}
双重锁定
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConsoleApp2
{
public partial class FormToolbox : Form
{
private static FormToolbox ftb = null;
//程序运行时创建一个静态只读的进程辅助对象
private static readonly object syncRoot = new object();
private FormToolbox()
{
InitializeComponent();
}
public static FormToolbox GetInstance()
{
if(ftb == null)
{
lock (syncRoot)//加锁
{
if (ftb == null || ftb.IsDisposed)
{
ftb = new FormToolbox();
ftb.MdiParent = Form1.ActiveForm;
}
}
}
return ftb;
}
}
}
现在这样,我们不用让线程每次都加锁,而只是在实例未被创建的时候再加锁处理。同时也能保证多线程的安全。这种做法被称为双重锁定。
静态初始化或饿汉式单例类
即在自己被加载时就将自己实例化。解决了多线程环境下它是不安全的问题。
谈不上更好,只不过实现更简单:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
//阻止发生派生,而派生可能会增加实例
public sealed class Singleton
{
//在自己被加载的时候就将自己实例化
private static readonly Singleton instance = new Singleton();
private Singleton() { }
public static Singleton GetSingleton() {
return instance;
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。