在面向对象设计模式中很多时候只希望对象只创建一个实例,因此出现了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等方法的用法与总结才实现了的。
总结,个人感觉学习编程的花时间最多的地方就是发现错误并改错,如果能改掉错误会有很强的成就感,但是很多时候即使改正了错误也说不出个所以然,因此需要学习的更深入更具体,防止下次出现同样的问题。最后感谢金旭亮老师开设这门课程,老师辛苦了~