我正在编写一个能够分配唯一ID的资源管理器(例如,对于OpenGL统一缓冲区绑定点,因此您不需要跟踪已使用的ID),所以如果有的话管理器的更多实例这将是一个问题,因为每个应该知道已经使用了哪些ID。 所以一种方法是使用Singleton:
class ResourceManager
{
private:
HandleAllocator uniform_binding_points;
...
public:
static ResourceManager& Get()
{
static ResourceManager resource_manager;
return resource_manager;
}
unsigned int AllocateUniformBindingPoint()
{ ... }
...
private:
ResourceManager()
{ }
~ResourceManager()
{ }
}
或者使用静态成员,因此可以有更多实例,但每个实例使用相同的状态:
class ResourceManager
{
private:
static HandleAllocator uniform_binding_points;
...
public:
unsigned int AllocateUniformBindingPoint()
{ ... }
...
}
所以我的问题是,区别是什么,以及是否有更好的解决方案(考虑可测试性)?我知道很多人都讨厌单身,但在我看来,唯一的区别是你需要使用Get()接收Singleton实例,这是一个方法调用更多,但你可以存储一个引用,所以你调用Get()一次。我也读过这个:http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/我需要说的是,通过合成和聚合,你可以实现完全相同的依赖隐藏",所以也不要使用它们? ...
答案 0 :(得分:2)
我认为这是一个风格问题,因此没有明确的答案。但是,我会说明为什么我认为单身人士是更好的解决方案。
Get
方法(我通常称之为instance
)清楚地说明这是一个单身人士(至少对于阅读过您的文档并且您的文档说它是单身人士的人来说)。您可以将多个引用初始化为
auto &mgr = ResourceManager::Get();
但他们都是一样的。它清楚地表明,对这些实例的任何函数调用都是对同一对象的调用。因此,可以更容易地遵循通常的指导方针。例如,如果应用程序具有多线程感知能力,那么我们就知道通常不应该在同一个对象上同时调用可变方法(前提是ResourceManager
的实现遵循这样的指导原则)。现在考虑静态成员方法,
ResourceManager mgr1;
ResourceManager mgr2;
如果我是一个用户并且不知道它是如何实现的,那么在这两个对象中的每一个上调用两个可变方法都没有任何损害,这是不正确的。简而言之,您可以更多地考虑Singleton"自我记录",至少对于了解Singleton是什么的用户而言。
此外,单例的不可复制属性也会在编译时更容易被检测到。
最后但并非最不重要的是,单身人士可以更灵活地管理长寿。在你的例子中,使用了迈耶的单身人士,因此没有太大的区别。但是如果需要,你可以改变单例的实现来微调它的寿命