C++ 单身替代方案
我有一个非常简单的游戏引擎。它使用了几个单例(我将列举其中的一些) 这些单身汉之间有很多电话。我将采用Events Manager示例用法:C++ 单身替代方案,c++,oop,design-patterns,C++,Oop,Design Patterns,我有一个非常简单的游戏引擎。它使用了几个单例(我将列举其中的一些) 这些单身汉之间有很多电话。我将采用Events Manager示例用法: 从监听器派生的任何对象都可以将itsel添加为某些事件的监听器,就像这样EventsManager->RegisterListener(this,&SomeClass::SomeMethod)(事件类型由SomeMethod参数推断) 任何其他对象都可以触发这样的事件EventsManager->PushEvent(SomeEvent) 在一些同步之后,事
EventsManager->RegisterListener(this,&SomeClass::SomeMethod)代码>(事件类型由SomeMethod参数推断)
EventsManager->PushEvent(SomeEvent)代码>
SomeClass<EventManager, RenderEngine,...>
关于这个主题,你能给我一些建议吗?你可以有一个全局“游戏”对象,它创建当前为单例的每个类的实例
有关EventManager的具体示例;侦听器基类可以提供派生类可以调用的register方法和push方法的实现
骨架定义:
class Listener
{
public:
virtual void ReceiveMessage( ... ) = 0;
protected:
void Register()
{
GetEventManagerSomehow()->RegisterListener( this, etc );
}
void PushEvent( etc )
{
GetEventManagerSomehow()->PushEvent( etc );
}
}
要解决在单例中检测资源泄漏的特定问题,请为每个单例类提供一个破坏实例的shutdown方法
class Singleton
{
// ...
static Singleton * GetInstance()
{
if (instance == NULL)
instance = new Singleton;
return instance;
}
static void Shutdown()
{
delete instance;
instance = NULL;
}
static Singleton * instance;
};
Singleton * Singleton::instance = NULL;
不是一个真正的答案,但可能太长了,无法发表评论 是单例的一个很好的替代方案:您在程序的主函数中创建实例,并将它们传递给“模块”(即主类),以便它们可以在本地使用它们。这意味着对于这些类,您将拥有您不想要的“复杂”构造函数。
然而,复杂性应该仅限于某些类,在我看来,传递一些依赖的“模块”并没有那么复杂。另外,您可以通过查看构造函数或主函数来找出模块之间的依赖关系
依赖项注入被大量使用,因为它确实解决了您所看到的问题(以及更多的问题,比如单元测试),只增加了非常有限的复杂性。为什么您想摆脱单例?我想,与其将所有单例都放在命名空间范围内,不如将实例放在一个对象中(通常只有一个,测试除外).然后,当你开始这样做时,考虑更多的分而治之。可能。是的,你为什么要删除单例?它们可能是最合适的模式。根据你的哲学,我一直认为,如果你想确保应用程序中只有一个对象实例,那么最简单的方法就是create one。@giorashc我上一个关于单例的问题是内存泄漏检测。我覆盖new/delete,我想在“end”转储分配的未删除内存。你能告诉我在这种环境中“end”是什么时候吗?对于我的问题,“hub”的想法很好。这样,我只有一个单例,即“hub”所有东西都在这里创建/销毁,可以通过“中心”访问。结合标记赎金建议,我可以删除“结尾”处的“中心”,或者我可以确定在“中心”析构函数中我没有任何全局变量。在发布此问题之前,我阅读了关于依赖注入的内容,我有一个问题(事件管理器:P):如何从任何模块的任何类使用PushEvent而不向这些类发送EventsManager的引用?也许在这种模式中我没有理解某些东西最直接的方法是将引用传递给构造函数。但是,这应该只对一些主类执行。较小的类可以检索引用根据需要从其“经理类”中删除,因此注入不必进入每个类。这将使代码不一致。在一个类中,必须使用SomeManager1->GetEventManager->PushEvent,而在另一个类中,必须使用SomeManager2->GetEventManager->PushEvent。这也将使一些类仅从代码的一部分可用(“manager类”)如果从模块的角度来看,这并不矛盾(该程序被划分为包含自己的子模块和类集的功能部分)。如果您的程序是单解析的,并且您将一致性置于调制之上,则可能有一个可以访问的主类管理器(如user1158692)。您还可以将依赖项注入扩展到每个需要引用的类。这是一个设计选择,由您决定。
class Listener
{
public:
virtual void ReceiveMessage( ... ) = 0;
protected:
void Register()
{
GetEventManagerSomehow()->RegisterListener( this, etc );
}
void PushEvent( etc )
{
GetEventManagerSomehow()->PushEvent( etc );
}
}
class Singleton
{
// ...
static Singleton * GetInstance()
{
if (instance == NULL)
instance = new Singleton;
return instance;
}
static void Shutdown()
{
delete instance;
instance = NULL;
}
static Singleton * instance;
};
Singleton * Singleton::instance = NULL;