代码改变世界

设计模式学习1—使用单件模式解决对象重复申请问题

2009-08-16 15:12  独孤残云  阅读(554)  评论(0编辑  收藏  举报
写在开篇——本文纯面向初学设计模式的各位同道,自诩高手的各位高手们打开此页时请在第一时间点击浏览器关闭按钮~~
本文作者:月云
作者博客:http://www.cnblogs.com/kenkao
文章正文
最近一直在看李会军老师的《.net设计模式系列文章》,不断充盈自己编程思想的同时,对.net框架体系的认知也得到了前所未有的加深。再次对TerryLee大哥表示感谢~~
初学.net的大家可能都遇到过这样的情况:我们在一个C/S项目中新加入两个窗体,窗体二中某事件执行之后,窗体一中的某些元素要发生相应的变化。严格来讲,我们应极力避免这种类和类之间的强耦合关系,然而要达到所谓的“0耦合”却绝非易事,有时这种理想状态甚至根本就不可能达到。
假如我们真的遇到上述状况,而且在允许这两个窗体类间发生强耦合关系的前提下,我们要怎样实现相应的效果呢?
曾经,学校的老师教过我们一个土办法,比如我要实现点击弹出的窗体二上的按钮时改变窗体一上的label内容。
以下是窗体设计和源码:
窗体一:

Form1.cs
Code
窗体二:

Form2.cs
Code

注意:你是不能在窗体二中仿效窗体一,再new一个Form1对象的。因为这样一来,窗体二中诞生的窗体一对象便不是原来的窗体一对象了。从系统的角度来讲,他们申请的内存不是同一段,他们是不同的资源。

所以我们必须仿效代码中的办法,先在窗体一里初始化一个窗体2对象,然后再将窗体二对象中的一个未初始化的窗体一引用对象指向窗体一(有些指针的味道了~~),这样可以保证两个窗体一对象指向同一段内存。


不过,如果多个窗体间发生这种关系的话,代码写起来就相当的繁琐了,而且这种方法也只能同时关联两个窗体类,众多弊端暴露无遗。

前一段时间看到TerryLee大哥的文章中讲到有关“单件模式”的内容时,我几乎是在第一时间联想到自己曾经遇到的这个问题。试着写了一个Demo,果然很好的解决了这个问题。
窗体设计不变,以下是源代码:
Form1.cs
Code
Form2.cs
Code
大家通过上述两段代码不难看出:我对外屏蔽了两个窗体类默认的构造函数。这时,要想产生出相应的窗体类对象就必须借助于事先定义好的单件模式静态构造函数——Instance()。
大家再来看这个Instance()都做了哪些工作:如果实现定义好的静态窗体对象ObjFrm1、ObjFrm2为空,则调用实现屏蔽的构造函数产生一个实体对象,如果实体对象已经存在,则直接返回这个对象。通过上述机制,我们便保证了相应的类对象实体有且只有一个。这样一来,也就不会产生像之前遇到的那种对象资源重复申请的问题了。
另外,将相应的单件模式构造函数和相应的窗体类实体对象定义成静态类型也是一个要点,这样一来我们就不需再依赖于现有的类对象资源。因为静态对象是不占用类资源的,他们是独立于类资源存在的。

此外,还有一个问题需要大家注意。大家务必要留意一下两次调用Instance()的时机——因为调用它们可能会导致构造函数的执行,所以最好不要让Instance的调用依赖于构造函数的执行,否则如果调用时机选不好的话就会出现死循环了。

因为Form1是整个项目默认的起始点,因此,我们还要相应的改动Program.cs里的Application.Run()传入的参数,这个参数不能再是默认的Form1构造函数(因为已经对外屏蔽了),而应该是我们定义的单件模式构造函数Form1.Instance()。
Program.cs
Code
以上便是单件模式下的解决对象重复申请的方法,这个方法的要点便是人为的控制对象申请也就是构造函数调用的时机,从而实现了实体对象的唯一性。这样的方法同样适用于多个窗体间,而且优势更为明显。
不过,任何方法都不是万能的,它们也不过只能应对一类问题。有关单件模式的详细介绍以及其利弊,请参照李会军老师的相关文章。

参考资料:李会军老师《.net设计模式系列文章

源码下载 —— https://files.cnblogs.com/kenkao/SingletonDemo.rar