有些类也需要计划生育——单例模式

单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。

使用场景

通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

单例模式结构图

image.png

懒汉式单例类

懒汉式单例类,即要在第一次被引用时,才会将自己实例化。
比如,在主窗体上不同的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;
        }
    }
}

你可能感兴趣的:(c#,设计模式,winform)