Oop 如果不是单身,那又怎样?
所以我正在研究中间件层 我正在使用一个处理低级硬件交互的COM DLL,并为UI提供一个与硬件进行IO的接口 作为my layer设计的一部分,我们加入了一个contextmanager,它安排各种硬件来生成应用程序可以使用的上下文 因此,我想保证使用我的代码的开发人员有一个单独的上下文管理器,然后在该上下文管理器中,我可以保证每个硬件设备只分配一个工作队列 更复杂的是,在我开始添加硬件设备之前,必须进行一些初始化。如果不是因为您通常只通过只读属性访问一个单例,那么这将非常简单 我知道单例模式会使很多事情变得困难,因为它具有全局可访问性。我真的不想,也不需要这个类有一个单一的全球可用性,我只想保证只有一个将在应用程序内创建 为此,我会疯狂地做这样的事情,基本上给我的单体一个构造函数:Oop 如果不是单身,那又怎样?,oop,singleton,Oop,Singleton,所以我正在研究中间件层 我正在使用一个处理低级硬件交互的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引擎使用它做其他事情。我不担心多重引用,我只是担心它被滥用,因为全局存储没有被精确地传递。