代码之家  ›  专栏  ›  技术社区  ›  Joel Barsotti

如果不是单身,那又怎样?

  •  2
  • Joel Barsotti  · 技术社区  · 17 年前

    所以我在研究中间件层。

    我正在使用一个处理低级硬件交互的COM DLL,并为UI提供一个与硬件进行IO的接口。

    作为我的层设计的一部分,我们放入了一个ContextManager,它安排各种硬件以生成应用程序可以使用的上下文。

    因此,我想保证使用我的代码的开发人员有一个单独的上下文管理器,然后在该上下文管理器内,我可以保证每个硬件设备只分配一个工作队列。

    为了使这复杂化,在我开始添加硬件设备之前,必须进行一些初始化。如果不是因为通常只通过一个只读属性访问一个单例,那就简单了。

    我知道单件模式会让很多事情变得困难,因为它是全球可访问的。我真的不想,也不需要这个类有一个单独的全局可用性,我只想保证在应用程序中只创建一个。

    为此,我会疯狂地做这样的事情,基本上给我的singleton一个构造函数:

    public class MySingleton
    {
     private static MySingleton _MySingleton;
     private static object singletonLock = new object();
    
     private MySingleton(int foo1, string foo2)
     {
      //do init stuff
     }
    
     public static MySingleton StartSingleton(int foo1, string foo2)
     {
      try
      {
       Monitor.Enter(singletonLock);
       if (_MySingleton == null)
       {
        _MySingleton = new MySingleton(foo1, foo2);
       }
       else
        throw new Exception("Singleton already initialized");
      }
      finally
      {
       Monitor.Exit(singletonLock);
      }
      return _MySingleton;
     }
    
     public static MySingleton Instance
     {
      get
      {
       try
       {
        Monitor.Enter(singletonLock);
        if (_MySingleton == null)
        {
         throw new Exception("Singleton must be Initialized");
        }
       }
       finally
       {
        Monitor.Exit(singletonLock);
       }
       return _MySingleton;
      }
     }
    }
    
    3 回复  |  直到 17 年前
        1
  •  4
  •   vava    17 年前

    这不是一个疯狂的代码,但它还是一个单身汉。如果删除 Instance 那么它就不再是单身了。

    全球可及性并不是让单身汉讨厌的全部。让它们讨厌的是它们直接在整个系统中使用,而您无法跟踪所有这些用法。这就是为什么在多线程代码中这是一个噩梦,这也是为什么在单线程代码中进行单元测试是如此困难的原因。

    因此,如果这是您的代码,我建议您在应用程序初始化期间只创建一个对象,并使用依赖项注入或作为简单的构造函数参数传递它。如果它是一个库,那么您可以签入构造函数(如果它是第一个正在创建的对象)或不签入构造函数并引发异常,也可以像处理静态构造函数一样使用静态构造函数,但不使用 实例 属性,强制开发人员传递实例。

    像往常一样,你可以创建一个单例,毕竟它的所有重要的是,产品的工作和客户喜欢使用它,单例或没有单例并不真正重要。

        2
  •  1
  •   Zak    17 年前

    你不会疯的。单例通过命名来避免全局变量的缺点。尽管它可以通过静态函数调用进行全局访问,但它不是全局变量。而且,它是通过一个名称空间访问的,所以没有人可能将它放在一个名为temp的全局变量中,然后将其他东西分配给temp。他们应该总是通过这样做得到当地的参考

    mysingleton singletoref=mysingleton.instance();

    当它们的作用域关闭时,引用将消失,因此它不是全局变量。

        3
  •  0
  •   Joel Barsotti    17 年前

    所以,如果我只是需要夸耀你只能创建我的对象的一个版本,那么这样的事情就会奏效:

    public class MySingleton
    {
        private static int objectCount = 0;
        private static object singletonLock = new object();
    
        public MySingleton(int foo1, string foo2)
        {
            try{
                Monitor.Enter(singletonLock);
                if (objectCount != 0)
                {
                    throw new Exception("MySingleton Already exsists");
                }
                else
                {
                    objectCount++;
                }
            }
            finally{
                Monitor.Exit(singletonLock);
            }
    
            //do initialization stuff
    
        }
    }
    

    显然不再是真正的单身汉了。