单件模式Singleton来控制窗体被重复或多次打开

简介: 本文转载:http://blog.csdn.net/a0700746/article/details/4473796 一般在百度搜一下,会出来一下内容,看来很好用。Singleton很方便的一个用处就是控制窗体被多次或重复打开。

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

一般在百度搜一下,会出来一下内容,看来很好用。Singleton很方便的一个用处就是控制窗体被多次或重复打开。下面是它的用法。

 

 

一般Singleton模式通常有几种形式:


public class Singleton {

  private Singleton(){}

  //在自己内部定义自己一个实例,是不是很奇怪?
  //注意这是private 只供内部调用

  private static Singleton instance = new Singleton();

  //这里提供了一个供外部访问本class的静态方法,可以直接访问  
  public static Singleton getInstance() {
    return instance;   
   } 
} 

 
 

第二种形式:

public class Singleton { 
  private static Singleton instance = null;

  public static synchronized Singleton getInstance() {

  if (instance==null)
    instance=new Singleton();
  return instance;   } 

} 

 
 

使用Singleton.getInstance()可以访问单态类。

上面第二中形式是lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。

注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论,有兴趣者进一步研究。

一般认为第一种形式要更加安全些。

使用Singleton注意事项:
有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的。

我们以SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocator为例稍微分析一下:

在Pet Store中ServiceLocator有两种,一个是EJB目录下;一个是WEB目录下,我们检查这两个ServiceLocator会发现内容差不多,都是提供EJB的查询定位服务,可是为什么要分开呢?仔细研究对这两种ServiceLocator才发现区别:在WEB中的ServiceLocator的采取Singleton模式,ServiceLocator属于资源定位,理所当然应该使用Singleton模式。但是在EJB中,Singleton模式已经失去作用,所以ServiceLocator才分成两种,一种面向WEB服务的,一种是面向EJB服务的。

Singleton模式看起来简单,使用方法也很方便,但是真正用好,是非常不容易,需要对Java的类 线程 内存等概念有相当的了解。

总之:如果你的应用基于容器,那么Singleton模式少用或者不用,可以使用相关替代技术。

 

 

 

以下是本人在实际的项目中的具体灵活运用,希望能帮到大家的忙。



问题描述:用了单件模式Singleton来控制窗体被重复或多次打开,最初是在MDI子窗体中写方法,后来看别人的写的是属性,基本是一样的,都可以,然后想的是,项目中有诺多窗体,如果每个窗体都写一份,岂不太脑残?所以打算写一个基类,但是呢,Singleton只能被实例化一次,所以只好用了泛型来写。基类终于写好了,然后调试,发现确实可以控制窗体的打开个数,即被多次打开,但是呢,当窗体操作完成并关闭后,,再次打开这个窗体时就会出现(无法访问已释放的对象)的错误。 这里呢就有关系到C#中的垃圾回收问题。C#垃圾回收器管理所有的托管对象,所有需要托管数据的.NET语言(包括 C#)都受运行库的垃圾回收器的制约。垃圾回收器可以确定运行垃圾回收的最佳时间,自动进行垃圾回收。然而垃圾回收的一个产物是:C#对象没有确定性毁坏。所以会出现子窗口对象已被销毁,但又不为null,故出现访问时产生“未处理 ObjectDisposedException”异常(来自于“从小处看C#.net垃圾回收”一文)。

       这里呢关于这个问题,因为不是主体所涉及,就不过多赘述,有兴趣的请大家自己查阅相关资料。回到正题,这又怎么办呢,有办法。问题的关键是,窗体已被释放,但因为还未来得及被系统处理,所以有Instance.Isdisposed=true,而Instance却不等null;怎么办呢,在窗体关闭的时候,可以人为地将其置为null;然后问题又出来了,Singleton为只读啊,如果你为Instance赋值,系统会报错,Instance为只读。怎么办呢,没办法,不撞南墙不回头,下定决心就做下去。要让它能被赋值,只能加上一个set了,这样再调试,一切就问题解决了。首先,窗体的重复或多次打开问题解决了;然后呢,每个窗体打开时,只要一行代码就搞定了,不用每个窗体写一份属性,方法(其实质还是借鉴Singleton);最后呢,不会出现再次打开不能访问的问题,即无法访问已释放的对象的问题。





以下是Singleton基类C#代码:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace dchtgl
{
    //泛型实现实例单件化
    public class Singleton<T> where T :new()
    {
        private static T instance = default(T);
        private static readonly object lockHelper = new object();
        private Singleton() { }
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (lockHelper)
                    {
                        if (instance == null)
                        {
                            instance = new T();
                        }
                    }
                }
                return instance;
            }
            set
            {
                instance = value;
            }
        }

    }
}







如果要在主窗体中打开某个窗体,比如Form1,代码如下:

//Form1为MDI子窗体

private void 会员管理ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form1  F1 = Singleton<Form1>.Instance;
            F1.MdiParent = this;
            F1.Show();

        }



但要注意的是,必须在该窗体关闭时,加上

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Singleton<Form1>.Instance = null;
        }
这样才不会出问题。这回应该清楚了吧。









对于这个问题,最近有了新的认识,把代码贴出来以飨读者。



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace dchtgl
{
    /// <summary>
    /// 泛型实现窗体实例单件化
    /// </summary>
    /// <typeparam name="T">窗体类</typeparam>
    public static class Singleton<T> where T : Form, new()
    {
        private static T instance = default(T);
        private static readonly object lockHelper = new object();

        /// <summary>
        /// 获取窗体的唯一实例
        /// </summary>
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (lockHelper)
                    {
                        if (instance == null)
                        {
                            instance = new T();

                            //加上实例关闭事件,窗体就会自动回收,即instance=null;
                            instance.FormClosed += new FormClosedEventHandler(DestroyForm);
                        }
                    }
                }
                return instance;
            }
        }

        /// <summary>
        /// 当窗体关闭时将Instance置空
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void DestroyForm(object sender, FormClosedEventArgs e)
        {
            instance = default(T);
        }

    }
}



用法同上,但是不必在窗体关闭的时候,加上

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Singleton<Form1>.Instance = null;
        }
这一句了。

  

目录
相关文章
|
10月前
|
前端开发 Linux C#
一款开源、免费、美观的 Avalonia UI 原生控件库 - Semi Avalonia
一款开源、免费、美观的 Avalonia UI 原生控件库 - Semi Avalonia
871 10
|
JSON Ubuntu 持续交付
用skopeo检查docker image
通过Skopeo,您可以方便地获取Docker镜像的详细信息和元数据,而不需要拉取或安装整个镜像。这对于那些有成百上千镜像的大型系统是非常实用的,因为它有助于快速查看和分析镜像的特定属性。Skopeo是一个专业的工具,用于在持续集成和部署的过程中实现高效的镜像管理,既减轻了对Docker守护进程的依赖,也为容器化环境中镜像的控制提供了灵活性。
226 3
|
架构师 安全 程序员
软考资料-分享
本文提供了计算机软考资源分享,包括高级、中级和初级三个层次的专业课程。高级课程如系统架构师、网络规划设计师等,中级课程如网络工程师、数据库系统工程师等,初级课程如网络管理员、程序员等,覆盖了多种专业方向,适合不同水平的学习者。
5913 0
|
域名解析 弹性计算 安全
阿里云服务器搭建个人WordPress网站博客流程
阿里云服务器搭建个人WordPress网站博客流程,使用阿里云服务器快速搭建网站教程,先为云服务器安装宝塔面板,然后在宝塔面板上新建站点,阿里云服务器网以搭建WordPress网站博客为例,来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流程:
608 0
|
Linux 计算机视觉 iOS开发
使用ffmpeg将MP4转换为WebM格式
使用ffmpeg将MP4转换为WebM格式
2434 2
|
Java
hashmap 的重新散列和装载因子
HashMap 的装载因子是 0.75
160 0
|
消息中间件 数据可视化 Oracle
LogStash的安装(传统方式&Docker)与使用
LogStash的安装(传统方式&Docker)与使用
860 0
|
C#
如何将图片内嵌到 Markdown 文档中,Markdown 如何使用 Data URL
我在云栖社区的聚能聊中发布了一个话题:“markdown编辑器与富文本编辑器之争,哪一个你最钟情?”。 其中有回复提到: markdown轻巧归轻巧,但也有硬伤,比如插入的图片如何保存的问题。几乎所有的markdown工具都会把图片单独保存在一个地方,这就是说你把自己的.md文件拷贝给别人的时候,还得把图片一并拷给他,而且路径要一模一样!这是妈蛋工具最大的吐槽点,图片就是处理的不好,就是这一点比不上office。
2404 0
|
5天前
|
弹性计算 人工智能 安全
云上十五年——「弹性计算十五周年」系列客户故事(第二期)
阿里云弹性计算十五年深耕,以第九代ECS g9i实例引领算力革新。携手海尔三翼鸟、小鹏汽车、微帧科技等企业,实现性能跃升与成本优化,赋能AI、物联网、智能驾驶等前沿场景,共绘云端增长新图景。