本文转载:http://blog.csdn.net/a0700746/article/details/4473796

  1. 一般在百度搜一下,会出来一下内容,看来很好用。Singleton很方便的一个用处就是控制窗体被多次或重复打开。下面是它的用法。
  2.  
  3. 一般Singleton模式通常有几种形式:
  4.  
  5. public class Singleton {
  6.  
  7.   private Singleton(){}
  8.  
  9.   //在自己内部定义自己一个实例,是不是很奇怪?
  10.   //注意这是private 只供内部调用
  11.  
  12.   private static Singleton instance = new Singleton();
  13.  
  14.   //这里提供了一个供外部访问本class的静态方法,可以直接访问  
  15.   public static Singleton getInstance() {
  16.     return instance;   
  17.    }
  18. }
  19.  
  20. 第二种形式:
  21.  
  22. public class Singleton {
  23.   private static Singleton instance = null;
  24.  
  25.   public static synchronized Singleton getInstance() {
  26.  
  27.   if (instance==null)
  28.     instancenew Singleton();
  29.   return instance;   }
  30.  
  31. }
  32.  
  33. 使用Singleton.getInstance()可以访问单态类。
  34.  
  35. 上面第二中形式是lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。
  36.  
  37. 注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。关于lazy initializationSingleton有很多涉及double-checked locking (DCL)的讨论,有兴趣者进一步研究。
  38.  
  39. 一般认为第一种形式要更加安全些。
  40.  
  41. 使用Singleton注意事项:
  42. 有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的。
  43.  
  44. 我们以SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocator为例稍微分析一下:
  45.  
  46. Pet StoreServiceLocator有两种,一个是EJB目录下;一个是WEB目录下,我们检查这两个ServiceLocator会发现内容差不多,都是提供EJB的查询定位服务,可是为什么要分开呢?仔细研究对这两种ServiceLocator才发现区别:在WEB中的ServiceLocator的采取Singleton模式,ServiceLocator属于资源定位,理所当然应该使用Singleton模式。但是在EJB中,Singleton模式已经失去作用,所以ServiceLocator才分成两种,一种面向WEB服务的,一种是面向EJB服务的。
  47.  
  48. Singleton模式看起来简单,使用方法也很方便,但是真正用好,是非常不容易,需要对Java的类 线程 内存等概念有相当的了解。
  49.  
  50. 总之:如果你的应用基于容器,那么Singleton模式少用或者不用,可以使用相关替代技术。
  51.  
  52. 以下是本人在实际的项目中的具体灵活运用,希望能帮到大家的忙。
  53.  
  54. 问题描述:用了单件模式Singleton来控制窗体被重复或多次打开,最初是在MDI子窗体中写方法,后来看别人的写的是属性,基本是一样的,都可以,然后想的是,项目中有诺多窗体,如果每个窗体都写一份,岂不太脑残?所以打算写一个基类,但是呢,Singleton只能被实例化一次,所以只好用了泛型来写。基类终于写好了,然后调试,发现确实可以控制窗体的打开个数,即被多次打开,但是呢,当窗体操作完成并关闭后,,再次打开这个窗体时就会出现(无法访问已释放的对象)的错误。 这里呢就有关系到C#中的垃圾回收问题。C#垃圾回收器管理所有的托管对象,所有需要托管数据的.NET语言(包括 C#)都受运行库的垃圾回收器的制约。垃圾回收器可以确定运行垃圾回收的最佳时间,自动进行垃圾回收。然而垃圾回收的一个产物是:C#对象没有确定性毁坏。所以会出现子窗口对象已被销毁,但又不为null,故出现访问时产生“未处理 ObjectDisposedException”异常(来自于“从小处看C#.net垃圾回收”一文)。
  55.  
  56. 这里呢关于这个问题,因为不是主体所涉及,就不过多赘述,有兴趣的请大家自己查阅相关资料。回到正题,这又怎么办呢,有办法。问题的关键是,窗体已被释放,但因为还未来得及被系统处理,所以有Instance.Isdisposed=true,而Instance却不等null;怎么办呢,在窗体关闭的时候,可以人为地将其置为null;然后问题又出来了,Singleton为只读啊,如果你为Instance赋值,系统会报错,Instance为只读。怎么办呢,没办法,不撞南墙不回头,下定决心就做下去。要让它能被赋值,只能加上一个set了,这样再调试,一切就问题解决了。首先,窗体的重复或多次打开问题解决了;然后呢,每个窗体打开时,只要一行代码就搞定了,不用每个窗体写一份属性,方法(其实质还是借鉴Singleton);最后呢,不会出现再次打开不能访问的问题,即无法访问已释放的对象的问题。
  57.  
  58. 以下是Singleton基类C#代码:
  59.  
  60. using System;
  61. using System.Collections.Generic;
  62. using System.Linq;
  63. using System.Text;
  64.  
  65. namespace dchtgl
  66. {
  67. //泛型实现实例单件化
  68. public class Singleton<T> where T :new()
  69. {
  70. private static T instance = default(T);
  71. private static readonly object lockHelper = new object();
  72. private Singleton() { }
  73. public static T Instance
  74. {
  75. get
  76. {
  77. if (instance == null)
  78. {
  79. lock (lockHelper)
  80. {
  81. if (instance == null)
  82. {
  83. instance = new T();
  84. }
  85. }
  86. }
  87. return instance;
  88. }
  89. set
  90. {
  91. instance = value;
  92. }
  93. }
  94.  
  95. }
  96. }
  97.  
  98. 如果要在主窗体中打开某个窗体,比如Form1,代码如下:
  99.  
  100. //Form1为MDI子窗体
  101.  
  102. private void 会员管理ToolStripMenuItem_Click(object sender, EventArgs e)
  103. {
  104. Form1 F1 = Singleton<Form1>.Instance;
  105. F1.MdiParent = this;
  106. F1.Show();
  107.  
  108. }
  109.  
  110. 但要注意的是,必须在该窗体关闭时,加上
  111.  
  112. private void Form1_FormClosed(object sender, FormClosedEventArgs e)
  113. {
  114. Singleton<Form1>.Instance = null;
  115. }
  116. 这样才不会出问题。这回应该清楚了吧。
  117.  
  118. 对于这个问题,最近有了新的认识,把代码贴出来以飨读者。
  119.  
  120. using System;
  121. using System.Collections.Generic;
  122. using System.Linq;
  123. using System.Text;
  124. using System.Windows.Forms;
  125.  
  126. namespace dchtgl
  127. {
  128. /// <summary>
  129. /// 泛型实现窗体实例单件化
  130. /// </summary>
  131. /// <typeparam name="T">窗体类</typeparam>
  132. public static class Singleton<T> where T : Form, new()
  133. {
  134. private static T instance = default(T);
  135. private static readonly object lockHelper = new object();
  136.  
  137. /// <summary>
  138. /// 获取窗体的唯一实例
  139. /// </summary>
  140. public static T Instance
  141. {
  142. get
  143. {
  144. if (instance == null)
  145. {
  146. lock (lockHelper)
  147. {
  148. if (instance == null)
  149. {
  150. instance = new T();
  151.  
  152. //加上实例关闭事件,窗体就会自动回收,即instance=null;
  153. instance.FormClosed += new FormClosedEventHandler(DestroyForm);
  154. }
  155. }
  156. }
  157. return instance;
  158. }
  159. }
  160.  
  161. /// <summary>
  162. /// 当窗体关闭时将Instance置空
  163. /// </summary>
  164. /// <param name="sender"></param>
  165. /// <param name="e"></param>
  166. private static void DestroyForm(object sender, FormClosedEventArgs e)
  167. {
  168. instance = default(T);
  169. }
  170.  
  171. }
  172. }
  173.  
  174. 用法同上,但是不必在窗体关闭的时候,加上
  175.  
  176. private void Form1_FormClosed(object sender, FormClosedEventArgs e)
  177. {
  178. Singleton<Form1>.Instance = null;
  179. }
  180. 这一句了。

  

单件模式Singleton来控制窗体被重复或多次打开的更多相关文章

  1. 设计模式 - 单件模式(singleton pattern) 具体解释

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u012515223/article/details/28595349 单件模式(singleton ...

  2. 设计模式(二)单件模式Singleton(创建型)

    SINGLETON(单件)—对象创建型模式 几乎所有面向对象的程序中,总有一些类的对象需要是唯一的,例如,通过数据库句柄到数据库的连接是独占的.您希望在应用程序中共享数据库句柄,因为在保持连接打开或关 ...

  3. [MyBean-说明书]关于插件的单件模式(singleton),插件的共享模式

    [说明] 单件模式是一种用于确保整个应用程序中只有一个类实例. 想想我们的系统中有哪些方面可以应用到单件模式,比如大家常说的连接(ADOConnection)共享,其实就是指的单件模式. [MyBea ...

  4. C#设计模式——单件模式(Singleton Pattern)

    一.概述在软件开发过程中,我们有时候需要保证一个类仅有一个实例,比如在一个电脑用户下只能运行一个outlook实例.这时就需要用到单件模式.二.单件模式单件模式保证一个类仅有一个实例,并提供一个访问它 ...

  5. 说说设计模式~单件模式(Singleton)

    单件模式(Singleton)要求一个类有且仅有一个实例,并且提供了一个全局的访问点. 从概念上来研究一下它的实现,不考虑线程安全 1 public sealed class Singlton 2 { ...

  6. 夜话JAVA设计模式之单例模式(单件模式Singleton)

    单例模式也叫单件模式,就是确保一个类只有一个实例,并提供一个全局访问点. 设计成单例即把某个类设计成我们自己管理的单独实例,避免实例对象的重复创建,我们只有通过单例类的全局访问点获取实例. 下面来看金 ...

  7. 设计模式----创建型型模式之单件模式(Singleton pattern)

    单件模式,又称单例模式,确保一个类只有一个实例,并提供全局访问点. 单件模式是比较简单且容易理解的一种设计模式.只有一个实例,通常的做法...TODO 类图比较简单,如下所示: 示例代码: 懒汉模式( ...

  8. 单件模式(Singleton)C++实现

    意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 实用性:1.当类只能有一个实例而且客户可以从一个众所周知的访问点访问它. 2.当这个唯一的实例应该是通过子类可扩展的,并且客户应该无需更改 ...

  9. 1.单件模式(Singleton Pattern)

    意图:为了保证一个类仅有一个实例,并提供一个访问它的全局访问点. 1.简单实现(多线程有可能产生多个实例) public class CommonSigleton { /// <summary& ...

随机推荐

  1. csv文本编辑引号问题

    今天发现一个csv的一个问题,csv工具类对于引号默认有特殊的处理.我希望写出来的结果是 1,"1",1 原来的代码是 CsvWriter cw=new CsvWriter(&qu ...

  2. Windows的命令行怎么支持通配符

    摸索出一个小技巧,虽然Windows的命令行本身不支持通配符,但可以在脚本里把传进来的参数当通配符用 只要加上@ARGV = glob "@ARGV";就行了 @ARGV = gl ...

  3. 反射给对象赋值遇到的问题——类型转换[转http://blog.csdn.net/xiaohan2826/article/details/8536074]

    发布时间:2012-10-25 10:49浏览次数:225 给一个对象属性赋值可以通过PropertyInfo.SetValue()方式进行赋值,但要注意值的类型要与属性保持一致.   创建对象实例的 ...

  4. Android自定义View基础

    自定义控件, 视频教程 http://www.jikexueyuan.com/course/1748.html 1. 编写自定义view 2. 加入逻辑线程 3. 提取和封装自定义view 4. 利用 ...

  5. .NET 4.0 使用 asyn await

    .NET 4.0 也可以使用asyn await 使用nuget 搜索await即可发现微软官方包,安装导项目就可以使用了.   参考:http://stackoverflow.com/questio ...

  6. 用链表解决if语句过多的问题(C/C++实现)

    起因 http://www.cnblogs.com/code-style/p/3499408.html 设计模式的解决方案(基于python语言) http://www.cnblogs.com/cod ...

  7. C++标准库的数值极限numeric_limits

    包含头文件:#include<limits> 它是一个模板类,它主要是把C++当中的一些内建型别进行了封装,比如说numeric_limits<int>是一个特化后的类,从这个 ...

  8. 详解Spring中的CharacterEncodingFilter

    在项目中有很多让人头疼的问题,其中,编码问题位列其一,那么在Spring框架中是如何解决从页面传来的字符串的编码问题的呢?下面我们来看看Spring框架给我们提供过滤器CharacterEncodin ...

  9. 【Linux】鸟哥的Linux私房菜基础学习篇整理(七)

    1. test命令的测试功能.测试的标志:(1)关于文件类型的检测 test [-efdbcSpL] filename-e:该文件名是否存在:-f:该文件名是否为文件:-d:该文件名是否为目录:-b: ...

  10. For循环练习之99乘法表和转义字符

    之前说了for循环的概念以及常用到的操作,那么我们接下来做几个巩固练习: 1.打印99乘法表: 99乘法表的形式: 1*1 = 1 1*2 = 2 2*2 = 4 1*3 = 3 2*3 = 6 3* ...