我不知道这是否真的符合DI的要求,因为我不是在谈论注入抽象依赖的具体实现。我只是在说注射需要的东西。
在我的游戏引擎中,我想要清理处理游戏状态的部分(菜单、舞台选择、游戏中、动画场景等)。所有这些东西都实现了一个公共接口。但其中一个,在游戏中,也被特别引用为当前正在玩的级别。
现在在我的项目中有43个引用到当前的级别,通过游戏访问,一个单例。例如,Game.CurrentGame.CurrentMap.Something。引用在屏幕、实体、行为组件中,甚至在主窗体中(用于调试工具)。
我想通过注入所有需要的东西来摆脱这个引用。但是CurrentMap本身并不是所需的依赖项--它下面的其他东西正在被访问。所以我最初的计划是进入每个地方,找到实际正在使用的东西,并通过向类构造函数添加一个参数来注入它。这引入了另一个上一层的依赖,所以我重复这个过程,直到一切都完成。但这样做的问题是,它将引入更多的构造函数参数,包括不直接使用依赖项的地方。许多类最终会接受一个依赖项,这样它们就可以将它传递给它们下面的另一个对象。
有什么比这更干净的选择呢?
发布于 2011-10-20 14:59:42
您正在讨论的场景中,依赖项必须通过几层对象才能到达真正需要它们的位置。这不需要发生。
如果一个对象自己创建了依赖项,那么你就会遇到这个问题。如果对象被工厂或DI容器(这只是一个花哨的工厂)提供了它所需要的依赖关系,那么你就不会有这个问题了。因此,为了避免这个问题,您需要决定每个类是与游戏逻辑相关还是与创建类相关。
假设你有object a,它调用object b,它调用object c,object c需要当前级别,而object b不需要。
错误的做法是从b内部调用new C(level);。正如您所指出的,b不需要知道级别,所以看起来事情正在变得更糟,而不是更好。您在依赖注入方面走得还不够远。不用在b中创建c,只需在b的构造函数中请求c即可。现在b类只知道c,对level一无所知。
Misko已经比我在这里解释得更好了,http://misko.hevery.com/2009/03/30/collaborator-vs-the-factory/
工厂中的代码如下所示:
Level level = new Level();
C c = new C( level );
B b = new B( c );
A a = new A( b );类B只知道它的直接合作者(c),并且不依赖于Level。因为我们是在工厂中创建对象,所以没有必要通过对象图向下传递对象图的叶子。
如果B类负责创建c,那么它需要知道如何创建c类的实例。这是错误的。
发布于 2011-10-20 11:26:08
考虑使用依赖注入框架,如Castle Windsor,Structuremap或Unity (还有许多其他非常可靠的框架)。
您描述的问题并不是这些框架解决的唯一问题,但它是它们几乎完全消除的摩擦类型中的一大部分。
依赖关系是具体的实现,而不是更高级别的抽象,这一事实无关紧要。看看这个问题(由你真正提出的):
发布于 2011-10-20 11:28:13
通常我会注入一个跟踪当前状态的服务:
public interface IGameStateTracker
{
Game CurrentGame {get;}
GameMap CurrentMap {get;}
}您应该只需要将此服务注入到将直接需要它的类的构造函数中。恐怕我不能完全理解为什么您发现需要将一些东西注入到不直接需要它的类中:这可能是您没有使用正确的依赖注入模式的迹象。你能提供一些代码样本来展示这个问题的一个例子吗?
我赞同Phil Sandler关于使用依赖注入框架的观点。这将使生活变得容易得多。但这并不能弥补最初使用不正确的依赖注入模式。
https://stackoverflow.com/questions/7830740
复制相似问题