用Singleton保护资源

Guarding resources with Singleton?

本文关键字:资源 保护 Singleton      更新时间:2023-10-16

我读了不少博客文章和关于SO的回答,指出Singleton是一个糟糕的设计。以前我实现了一个单例camercontrol类。这个类控制一个连接到系统的摄像机。根据以下知识:

  • 在任何情况下都不能有超过一个摄像机(摄像机制造商提供的摄像机API控制所有摄像机)。
  • 在多个地方同时使用相机制造商的API在过去已经引起了问题(例如一个线程试图抓取图像,另一个线程试图设置快门速度)。我的类只提供了几个额外的方法来显示在UI中捕获的图像。将图像转发到人脸检测器,…(即它不是内存密集型的)。

我选择使这个类成为单例类是一个错误的决定吗?

单例被认为是一种气味,因为:

  • 它们在道德上相当于全局变量,因此它们的使用隐藏了代码中的依赖关系,而不是通过接口显示它们。

  • 它们促进了紧密耦合,因为您的代码依赖于特定类型的特定实例。如果有一天你想让你的UI对不同的相机管理器操作怎么办?

  • 它们使单元测试变得困难,因为它们在程序的整个生命周期中都携带着状态。当状态从一个测试传递到另一个测试时,它可以使测试依赖于状态,这是一个非常大的气味。

你迟早可以读任何东西。不管怎样有些人说,没有根本的理由反对使用在适当情况下的单例_。在你的情况下,我有严重怀疑,至少你是这么说的。不管相机制造商的API(可能是C语言),你的客户端代码将希望将每个单独的相机视为一个单独的对象,没有什么固有的独特性相机。

的API可能适合使用单例模式相机制造商在C,你决定提供它的一个轻量级c++包装器,供(独占地)使用你的摄影课。这种轻量级的包装就是其中之一合法地使用单例——在这个世界上你不可能可以在代码中拥有该库的多个实例。(但是,通常使用Camera类地址更容易

我选择使这个类成为单例类是一个错误的决定吗?

是的。

  • 在任何情况下都不能有超过一个摄像机(摄像机制造商提供的摄像机API控制所有摄像机)。

这样就没有必要通过Singleton类来访问camera了。

  • 在多个地方同时使用相机制造商的API在过去已经引起了问题(例如一个线程试图抓取图像,另一个线程试图设置快门速度)。

使用单例类不会为你带来任何在非单例类中无法解决的问题。

    我的类只提供了几个额外的方法来显示在UI中捕获的图像。将图像转发到人脸检测器,…(即它不是内存密集型的)。

那么就没有必要创建一个类似于god的Singleton类了。

此外,你添加到Singleton类中的那些小而漂亮的helper功能,以及它们与其他代码段的交互,当驻留在具有全局状态的Singleton类中,不能在测试之间正确地设置和删除时,就不容易进行单元测试。

通过在应用程序组合根中正确使用依赖注入,具体对象的生命周期可以被管理,就好像它是一个单例,但是该对象的单个客户端不需要知道这一点。

我个人认为在适当的时候使用singleton是合理的。一般来说,它们肯定会被过度使用,但在我看来,它们对于控制硬件资源的管理器类是有用的,这就是您正在做的。

是和否

不,因为你看到的并发问题是你在处理线程时无法"安全"避免的问题。糟糕的同步机制迟早会找上门来,破坏您可爱的代码。你将需要互斥锁和信号量等来保护资源。

是的,因为单例模式对于线程来说是一个糟糕的模式。看看这个关于单例的页面,你会看到一些与之相关的陷阱。基本上,你是在自找麻烦。

关于一般的"单例是邪恶的",这是因为它使弄清楚它是如何工作的更加困难,它们是全局变量的OOP版本。假设你在某个地方有一个单例,它在15个地方被修改,你如何跟踪它?如果你有一个"真实的"对象,你就能看到它是如何在参数中传递的。单例模式打破了作用域的概念,很容易变成一团糟。

SingletonMonostate模式在这方面都很有用。您的主要考虑(关于第二点)是防止多次访问,Singleton和Monostate都不能防止这一点。

是的,使它成为Singleton是一个糟糕的设计。如果你只需要一个Camera对象,那就创建一个。

如果你需要确保camera对象以不可重入的方式使用,那么这不是camera对象的责任,而是你的线程模型的责任。这是一个独立的工作。