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

时间:2009-10-05 23:23:57

标签: oop singleton

所以我正在开发一个中间件层。

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

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

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

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

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

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

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 个答案:

答案 0 :(得分:4)

这不是疯狂的代码,但无论如何它都是单身。如果删除Instance属性,则它将不再是单例。

全球可访问性并非让单身人士感到讨厌。令他们讨厌的是,他们直接在整个系统中使用,而无法跟踪所有这些用法。这就是为什么它在多线程代码中是如此噩梦,这就是为什么用单例内部单元测试任何东西都是如此困难。

因此,如果它是您的代码,我建议在应用程序初始化期间只创建一个对象,并使用依赖注入或普通构造函数参数传递它。如果它是一个库,你可以检查构造函数是否是第一个正在创建的对象并抛出异常,或者你可以像你一样使用静态构造函数但没有Instance属性,迫使开发人员传递实例

与往常一样,你可以创建单身,毕竟重要的是产品的运作和顾客喜欢使用它,单身或没有单身并不重要。

答案 1 :(得分:1)

你不会疯了。单例由于被命名空间而避免了全局变量的缺点。尽管它可以通过静态函数调用进行全局访问,但它不是全局变量。而且,它是通过命名空间访问的,因此没有人可能将它放在名为temp的全局变量中,然后将其他内容分配给temp。他们应该总是通过

获得本地参考

MySingleton singletonRef = MySingleton.Instance();

当它们的范围关闭时,引用就会消亡,因此它不是全局变量。

答案 2 :(得分:0)

因此,如果我只需要保证您只能创建我的对象的一个​​版本,那么这样的东西就会起作用:

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

    }
}

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