单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
懒汉式单例类,即要在第一次被引用时,才会将自己实例化。
比如,在主窗体上不同的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; } } }