Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 如果不是单身,那又怎样?_Oop_Singleton - Fatal编程技术网

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

Oop 如果不是单身,那又怎样?,oop,singleton,Oop,Singleton,所以我正在研究中间件层 我正在使用一个处理低级硬件交互的COM DLL,并为UI提供一个与硬件进行IO的接口 作为my layer设计的一部分,我们加入了一个contextmanager,它安排各种硬件来生成应用程序可以使用的上下文 因此,我想保证使用我的代码的开发人员有一个单独的上下文管理器,然后在该上下文管理器中,我可以保证每个硬件设备只分配一个工作队列 更复杂的是,在我开始添加硬件设备之前,必须进行一些初始化。如果不是因为您通常只通过只读属性访问一个单例,那么这将非常简单 我知道单例模式会

所以我正在研究中间件层

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

作为my layer设计的一部分,我们加入了一个contextmanager,它安排各种硬件来生成应用程序可以使用的上下文

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

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

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

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

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;
  }
 }
}

你不会疯的。单例通过名称空间避免了全局变量的缺点。尽管它可以通过静态函数调用全局访问,但它不是全局变量。而且,它是通过名称空间访问的,所以没有人可能会将它放在一个名为temp的全局变量中,然后再为temp分配其他内容。他们应该总是通过这样做来获得对它的本地引用

MySingleton singletonRef=MySingleton.Instance()


当它们的作用域关闭时,引用终止,因此它不是一个全局变量。

这不是疯狂的代码,但无论如何它是一个单例。如果您删除
实例
属性,那么它将不再是单例

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

所以,如果是您的代码,我建议您在应用程序初始化期间只创建一个对象,并使用依赖项注入或普通构造函数参数传递它。如果它是一个库,您可以签入构造函数(无论它是否是创建的第一个对象)并抛出异常,或者您可以像使用静态构造函数一样使用它,但不使用
Instance
属性,强制开发人员传递实例


像往常一样,您可以创建单例,毕竟重要的是产品工作正常,客户喜欢使用它,单例或无单例并不重要。

因此,如果我只需要夸耀您只能创建我的对象的一个版本,那么类似这样的事情就行了:

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

    }
}

显然不再是一个真正的单例。

“全局可访问性并不是单例令人讨厌的原因。让单例令人讨厌的是,它们在整个系统中直接使用,而您无法跟踪所有这些使用情况。”全局可访问性不是与不可跟踪的使用情况一致的吗?这完全取决于开发人员如何使用它。但是你是对的,它实际上是一个问题的一部分,但不是整个问题。一切都会耦合到单态,然后变得不稳定。请注意,一些依赖注入框架支持生命周期管理,这意味着您可以将任何类转换为单例,而不会有任何缺点。(除了我可能会使用“lock(singletonLock){…}”而不是监视器调用之外,我不确定是否有区别。)singleton本质上是类的静态常量实例,在第一次使用时初始化。通常,它在第一次调用实例方法时进行初始化,但是没有理由不能按照这里的方式进行初始化。请注意,它将在应用程序的生命周期中存在,就像静态文件一样;如果你正在使用硬件资源,你可能需要在应用程序退出之前进行一些清理。这是试图成为一个单身而不是单身。您是担心多线程并发访问,还是担心一次只存在1个?在代码中有多个对同一对象的引用是可以的。听起来你好像在什么地方听到过“单身汉不好”,并试图对此采取一些措施。每个程序都有一个全局入口点(psvm)。人们之所以说“单身不好”,是因为他们到处都有人打电话给他们。因此,请使用单例,但不要调用该方法从各地获取单例。显式传递ITI如果我控制了应用程序的两个部分,那么就可以了。我之所以在选择正确的设计模式时如此谨慎,是因为不仅我所在组织的开发人员可能会使用该中间件层,而且其他公司可能会授权该IO引擎使用它做其他事情。我不担心多重引用,我只是担心它被滥用,因为全局存储没有被精确地传递。