学习笔记(一)简单的Singleton实现

本文介绍了Singleton设计模式在C#中的应用,通过一个桌面应用的帮助文档显示功能来展示其实现。讨论了线程安全问题以及两种C#实现Singleton的方法,包括静态方法和结合线程安全的优化。在实践中遇到的异常问题如‘无法访问已释放的对象’和‘未将对象引用设置到对象的实例’进行了分析和解决,强调了错误调试和深入学习的重要性。
摘要由CSDN通过智能技术生成

在面向对象设计模式中很多时候只希望对象只创建一个实例,因此出现了Singleton设计模式,网易云课堂的课程《面向对象软件开发实践之基本技能训练》中第一章讲到了该设计模式,并留下编程作业:
请编写一个示例应用,应用Singleton设计模式实现某桌面应用的帮助文档显示功能。
要求:
(1)整个应用只有一个帮助窗体对象
(2)在不同的窗体压F1键,帮助文档窗体中应该显示不同的内容。

课程中讲了两种实现方法,第一种是

class Only
{
    private static Only obj = null;
    private Only()
    {
    }
    public static Only GetOnly()
    {
        if(obj == null)
            obj = new Only();
        return obj;
    }
}

这种方式有一个不好的地方在于,使用多线程编程时对象有可能重复创建导致线程不安全,可以使用lock等方法保证线程安全,但性能会有较大损失。因此借助C#运行平台CLR的方式,使用静态方法,代码如下。

class Only
{
    private static Only obj = null;
    private Only()
    {
    }

    //该方法为核心
    static Only()
    {
        obj = new Only();
    }
    public static Only GetOnly()
    {
        return obj;
    }
}

作业的要求不是很明确,于是从简出发,只用一个窗体程序实现。主窗体只有一个帮助按键,点击后弹出帮助窗体,或者使用keydown方法按F1实现该功能。使用try catch捕捉异常,代码如下

    private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                Help.GetHelp().Show();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

/*
注:先要将主框体的KeyPreview属性设置为true,否则按F1没反应。另外KeyPress事件无法捕捉F1,必须用KeyDown
*/
    private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if(e.KeyCode == Keys.F1)
                    Help.GetHelp().Show();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

Help窗体也只有一个确定按键,点击后关闭窗体,Help类代码如下,按照第二种方式实现的。

public partial class Help : Form
    {
        private Help()
        {
            InitializeComponent();
        }        

        private static Help obj = null;

        static Help()
        {
            obj = new Help();
        }

        public static Help GetHelp()
        {
            return obj;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }

运行之后发现问题,关闭Help窗体后再次点击主窗体的帮助则会产生异常【无法访问已释放的对象】。于是综合两种实现方式,在GetHelp中加入判定条件,并在确定键的方法中释放所有资源,将obj设为null。

public static Help GetHelp()
        {
            if (obj == null)
            {
                obj = new Help();
            }
            return obj;
        }
private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
            this.Dispose();
            obj = null;
        }

此时依旧有问题,即点击Help窗体右上角的X号关闭后再次点击帮助会捕获新的异常【未将对象引用设置到对象的实例】。个人不太能理解这句话,猜测原因出自关闭窗体,重写析构函数显然不可行,于是修改了关闭Help窗体的函数。

private void Help_FormClosed(object sender, FormClosedEventArgs e)
        {
            obj = null;
        }

此时运行该程序则不会出现问题。

最初这个程序是没有实现按F1功能的,后来是我查了KeyPress,KeyDown等方法的用法与总结才实现了的。

总结,个人感觉学习编程的花时间最多的地方就是发现错误并改错,如果能改掉错误会有很强的成就感,但是很多时候即使改正了错误也说不出个所以然,因此需要学习的更深入更具体,防止下次出现同样的问题。最后感谢金旭亮老师开设这门课程,老师辛苦了~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值