设计模式-单例模式

这也算是我所学习的第一个设计模式把,因为它最简单。但是仔细学一下就会发现,也不是很简单的,因为需要考虑很多问题。

写一个MDI窗口程序,当中有一个工具箱的窗体,希望工具箱要么不出现,要么出现一个,怎么做到呢?

可以用是否为null来判断,别忘了还有disposed的判断。如果有多处的话要写成函数。

但是,这样的话把是否实例化都写到Form中了,而Form里应该只是通知启动工具箱,至于工具箱窗体啊是否实例化过,这时他自己的责任,而不是别人的责任,别人应该只是使用它就可以了。

所有类都有构造方法,不编码则系统默认生成空的构造方法,若有显示定义的构造方法,默认的构造方法就会失效。

于是我们可以将工具箱类的构造方法写成是private的,对于外部代码,不能用new来实例化它,但是我们可以用GetInstance()方法,这个方法的目的就是返回一个类实例,在此方法中,去做是否有实例化的判断。如果没有实例化过,由调用private的构造方法new出这个实例。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Singleton
{
    public partial class FormToolBox : Form
    {
        //声明一个静态的类变量
        private static FormToolBox ftb = null;
        //构造方法私有,外部代码不能直接new来实例化它
        private FormToolBox()
        {
            InitializeComponent();
        }

        private void FormToolBox_Load(object sender, EventArgs e)
        {

        }
        //得到类实例的方法,返回值就是本类对象,注意也是静态的。
        public static FormToolBox GetInstance()
        {
            //从内部的ftb是null或者是Disposed过,则new它,并且设计其MdiParent为Form1,
            //此时将实例化的对象存在静态的变量ftb中,以后就可以不用实例而得到他了。
            if (ftb == null || ftb.IsDisposed)
            {
                ftb = new FormToolBox();
                ftb.MdiParent = Form1.ActiveForm;
            }
            return ftb;
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Singleton
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void 工具箱ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormToolBox.GetInstance().Show();
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            FormToolBox.GetInstance().Show();
        }
    }
}

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

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

单例模式因为Singleton类封装他的唯一实例,这样他可以严格地控制客户怎样访问它以及何时访问它,简单的说就是对唯一实例的受控访问。

在多线程的情况下我们怎么做呢?多个线程同时访问Singleton类,调用GetInstance()方法,会有可能造成创建多个实例的。

可以用lock。lock是确保当一个线程位于代码的临界区时,另一个线程不进入临界区,如果其他线程试图进入锁定的代码,则它讲一直等待,直到该对象被释放。

但是每次都要lock,很影响性能。

可以用双重锁定的方法:

class Singleton
{
    private static Singleton instance = null;
    private static readonly Object syncObject = new Object();

    private Singleton()
    {
    }

    public static Singleton GetInstance()
    {
       if (instance == null)
       {
          lock (syncObject)
          {
              if (instance == null)
                 instance = new Singleton();
           }
       }

       return instance;
    }
}

在外面已经判断了instance实例是否存在,为什么在lock里面还需要做一次instance实例是否存在的判断呢?

对于instance存在的情况,就直接放回,这没有问题。当instance为null并且同时有两个线程调用GetInstance()方法时,他们将都可以通过第一重instance == null的判断,然后由于lock机制,这两个线程则只有一个进入,另一个在外排队等候,必须要其中的一个进入并出来后,另一个才能进入。而此时如果没有了第二重的instance是否为null的判断,则第一个线程创建了实例,而第二个线程还是可以继续再创建新的实例,这就没有达到单例的目的。

C#与公共语言运行库也提供了一种静态初始化的方法,这种方法不需要开发人员显式地编写线程安全代码,即可解决多线程环境下它是不安全的问题。

//阻止发生派生,而派生可能会增加实例
sealed class Singleton
{
   //在第一次引用类的任何成员时创建实例,公共语言运行库负责处理变量初始化
   private static readonly Singleton instance = new Singleton();

   private Singleton()
   {
   }

   public static Singleton GetInstance()
   {
       return instance;
   }
}

这种静态初始化的方式是在自己被加载时就将自己实例化,所以被形象地称之为饿汗式单例类,原先的单例模式处理方式是要在第一次被引用时,才会将自己实例化,所以就被称为懒汉式单例类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值