我一直在阅读有关依赖注入的内容,并提出了一个简单的问题。我可以理解如何通过构造函数或setter注入所需的依赖项由DI框架自动装配。当对象决定由于某些业务流程而需要创建新对象时会发生什么?在这些情况下,我是否需要始终创建工厂?为了使它成为一个不那么抽象的问题,这是一个例子。
假设我正在写一个Asteriods游戏。中间有一艘船可以旋转并射击星号。假设已经创建了船并注入了适当的东西。调用playerShip.shoot()
时,我们需要创建一个bullet
对象。子弹对象需要知道它的走向(direction
)以及从哪里开始(point
)。
通常情况下,我会这样做:
bullet = new Bullet( direction, point );
然而,这将PlayerShip类与Bullet类紧密耦合。这应该如何在依赖注入下工作?我是否需要创建一个BulletFactory接口并将其实现注入到船中?
编辑:我实际上并没有写星号。这是一个我认为人们会理解的简单例子。我想要一些需要创建运行时的东西(不是在“连接对象”时),它也有参数给它的构造函数。
答案 0 :(得分:3)
取决于你是否只有一种子弹类型......
如果只有一个,那么我会说你没事。
但如果您有子弹,DoubleBullet,PowerBullet,NukeBullet等
然后我会制作Bullet基类和其他所有Derrived
然后我会制作Bullet工厂,它会有CreateBullet,CreatePowerBullet等。
另一个问题是其他任何事情都会成为一颗子弹吗?如果是这样,那么我会创建一个工厂来合并创建逻辑......
否则它就像使用DI一样,只是为了使用DI ......
答案 1 :(得分:2)
你已经得到了它。如果你想与Bullet
类解耦,那么在我看来,最好的解决方案是注入一个可以创建Bullet
个对象的工厂。
请注意,您可以采用多个级别的间接,每个级别都可以提供更多灵活性,但需要更多代码并且可能更难以理解。最简单的是让BulletFactory
和Bullet
都是具体类型。这意味着您不能轻易地拥有它们的不同实现,但您仍然可以扩展它们并传入BulletFactory
的子类,该子类返回Bullet
的子类。如果您注射的唯一目的是使单元测试更容易,这就是我要采取的路线。当然,您也可以使BulletFactory
成为界面,或Bullet
界面,或两者兼而有之。如果您要为非测试目的使用不同的工具,这就是我要采取的路线。
最后,您必须确定将Bullet
类与PlayerShip
类解耦的好处是否值得。紧耦合不是邪恶的,不应该不惜一切代价避免 - 它在某些情况下是有道理的,而在其他情况下则不然。只有经验才能帮助您确定何时结合课程以及何时将其分离。
答案 2 :(得分:1)
依赖注入不适合这种情况。如果您为此创建工厂,则会过度使用设计模式。你不能解耦整个系统,在这种情况下,Ship有一个带有Bullet的组合,如果你需要更复杂的东西,那么另一个模式(不一定是DI)就足够了。
答案 3 :(得分:1)
是的,这闻起来像过度架构。然而,在我的头脑中,你可以拥有一个存储子弹类型的属性,然后让你的DI框架(这里是ninject)创建子弹。
public Type BulletType {get; set;}
public void fire()
{
var b = (BulletType) kernel.get(BulletType);
b.fire(point, direction);
}