当方法需要创建新对象时,有关依赖注入的新手问题

时间:2020-12-11 11:33:37

I've been reading about dependency injection and have a simple question. I can understand how via constructor or setter injection required dependencies are autowired by the DI framework. What happens when an object decides it needs to create a new object due to some business process? Do I need to always create a Factory in these situations? To make it a less abstract question, here is an example.

我一直在阅读关于依赖注入的问题并且有一个简单的问题。我可以理解如何通过构造函数或setter注入所需的依赖项由DI框架自动装配。当对象决定由于某些业务流程而需要创建新对象时会发生什么?在这些情况下,我是否需要始终创建工厂?为了使它成为一个不那么抽象的问题,这里有一个例子。

Let's say I'm writing a game of Asteriods. There's a ship in the middle which can spin around and shoot the asteriods. Assume that the ship has been created and approriate things injected. When playerShip.shoot() is called we need to create a bullet object. The bullet object needs to know which way it is going (direction) and where to start (point).

假设我正在写一个Asteriods游戏。中间有一艘船可以旋转并射击星号。假设已经创建了船并注入了适当的东西。当调用playerShip.shoot()时,我们需要创建一个子弹对象。子弹对象需要知道它的走向(方向)以及从哪里开始(指向)。

Normally, I would do something like this:

通常,我会做这样的事情:

bullet = new Bullet( direction, point );

However, that tightly couples the PlayerShip class to the Bullet class. How should this work under dependency injection? Do I need to create a BulletFactory interface and inject an implementation of that into the ship?

但是,这将PlayerShip类与Bullet类紧密耦合。这应该如何在依赖注入下工作?我是否需要创建一个BulletFactory接口并将其实现注入到船中?

Edit: I'm not actually writing asteriods. This was a simple example that I thought people would understand. I wanted something that needed to be created a runtime (not while "wiring up objects") that also had parameters to it's constructor.

编辑:我实际上并没有写asteriods。这是一个我认为人们会理解的简单例子。我想要一些需要创建一个运行时(而不是“连接对象”)的东西,它也有它的构造函数的参数。

4 个解决方案

#1


Depends if you just going to have just one bullet type...

取决于你是否只有一种子弹类型......

If just one then I would say you'd be ok.

如果只有一个,那么我会说你会好的。

But if you have a Bullet, DoubleBullet, PowerBullet, NukeBullet, etc.

但是如果你有Bullet,DoubleBullet,PowerBullet,NukeBullet等。

Then I would make Bullet base class and all the other Derrived from it

然后我会从它制作Bullet基类和所有其他Derrived

Then I would make Bullet factory and it would have CreateBullet, CreatePowerBullet, etc.

然后我会制作Bullet工厂,它会有CreateBullet,CreatePowerBullet等。

The other question is will anything else be making a bullet? If so then I would create a factory to consolidate the creation logic in one place...

另一个问题是其他任何事情都会成为一颗子弹吗?如果是这样,那么我会创建一个工厂来在一个地方合并创建逻辑......

Otherwise it smells like your using DI just to be using DI...

否则它就像你使用DI一样只是为了使用DI ......

#2


You've pretty much got it. If you want to be decoupled with the Bullet class, then in my opinion the best solution is to inject a factory that can create Bullet objects.

你已经得到了它。如果你想与Bullet类解耦,那么在我看来,最好的解决方案是注入一个可以创建Bullet对象的工厂。

Note that you have several levels of indirection you can take, each giving you more flexibility, but requiring more code and possibly being more difficult to understand. The simplest is to have BulletFactory and Bullet both be concrete types. This means you can't easily have different implementations of them, but you can still extend them both and pass in a subclass of BulletFactory that returns subclasses of Bullet. If your only purpose for injection is to make unit tests easier, this is the route I would take. Of course, you can also make BulletFactory an interface, or Bullet an interface, or both. If you're going to have different implements of either for non-testing purposes, this is the route I would take.

请注意,您可以采用多个级别的间接,每个级别都为您提供了更大的灵活性,但需要更多代码并且可能更难以理解。最简单的是让BulletFactory和Bullet都是具体的类型。这意味着您不能轻易地拥有它们的不同实现,但您仍然可以扩展它们并传入BulletFactory的子类,该子类返回Bullet的子类。如果您注射的唯一目的是使单元测试更容易,这就是我要采取的路线。当然,您也可以将BulletFactory设置为接口,或者将Bullet设置为接口,或两者兼而有之。如果您要为非测试目的使用不同的工具,这就是我要采取的路线。

Finally, you have to decide if the benefits of decoupling the Bullet class from your PlayerShip class are worth it. Tight coupling is not evil and shouldn't be avoided at all costs—it makes sense in some contexts, and not in others. Only experience will help you figure out when to couple classes and when to decouple them.

最后,您必须确定将Bullet类与您的PlayerShip类分离的好处是否值得。紧耦合不是邪恶的,不应该不惜一切代价避免 - 它在某些情况下是有道理的,而在其他情况下则不然。只有经验才能帮助您确定何时结合课程以及何时将它们分离。

#3


The dependency injection is not suitable for this case. If you create a factory for this you will overuse design patterns. You can't decouple the entire system, in this case Ship has a composition with Bullet, and in case you need any more complex than that another pattern (not necessarily DI) might be adequate.

依赖注入不适用于这种情况。如果为此创建工厂,则会过度使用设计模式。你不能解耦整个系统,在这种情况下,Ship有一个带有Bullet的组合,如果你需要比其他更复杂的模式(不一定是DI)就足够了。

#4


Yes, this smells like over-architecting. Nevertheless, off the top of my head, you could have a property that stores the bullet Type and then have your DI framework (ninject here) create the bullet.

是的,这闻起来像是过度架构。然而,在我的脑海中,你可以拥有一个存储子弹类型的属性,然后让你的DI框架(这里是ninject)创建子弹。

public Type BulletType {get; set;}

public void fire()
{
    var b = (BulletType) kernel.get(BulletType);
    b.fire(point, direction);
}

#1


Depends if you just going to have just one bullet type...

取决于你是否只有一种子弹类型......

If just one then I would say you'd be ok.

如果只有一个,那么我会说你会好的。

But if you have a Bullet, DoubleBullet, PowerBullet, NukeBullet, etc.

但是如果你有Bullet,DoubleBullet,PowerBullet,NukeBullet等。

Then I would make Bullet base class and all the other Derrived from it

然后我会从它制作Bullet基类和所有其他Derrived

Then I would make Bullet factory and it would have CreateBullet, CreatePowerBullet, etc.

然后我会制作Bullet工厂,它会有CreateBullet,CreatePowerBullet等。

The other question is will anything else be making a bullet? If so then I would create a factory to consolidate the creation logic in one place...

另一个问题是其他任何事情都会成为一颗子弹吗?如果是这样,那么我会创建一个工厂来在一个地方合并创建逻辑......

Otherwise it smells like your using DI just to be using DI...

否则它就像你使用DI一样只是为了使用DI ......

#2


You've pretty much got it. If you want to be decoupled with the Bullet class, then in my opinion the best solution is to inject a factory that can create Bullet objects.

你已经得到了它。如果你想与Bullet类解耦,那么在我看来,最好的解决方案是注入一个可以创建Bullet对象的工厂。

Note that you have several levels of indirection you can take, each giving you more flexibility, but requiring more code and possibly being more difficult to understand. The simplest is to have BulletFactory and Bullet both be concrete types. This means you can't easily have different implementations of them, but you can still extend them both and pass in a subclass of BulletFactory that returns subclasses of Bullet. If your only purpose for injection is to make unit tests easier, this is the route I would take. Of course, you can also make BulletFactory an interface, or Bullet an interface, or both. If you're going to have different implements of either for non-testing purposes, this is the route I would take.

请注意,您可以采用多个级别的间接,每个级别都为您提供了更大的灵活性,但需要更多代码并且可能更难以理解。最简单的是让BulletFactory和Bullet都是具体的类型。这意味着您不能轻易地拥有它们的不同实现,但您仍然可以扩展它们并传入BulletFactory的子类,该子类返回Bullet的子类。如果您注射的唯一目的是使单元测试更容易,这就是我要采取的路线。当然,您也可以将BulletFactory设置为接口,或者将Bullet设置为接口,或两者兼而有之。如果您要为非测试目的使用不同的工具,这就是我要采取的路线。

Finally, you have to decide if the benefits of decoupling the Bullet class from your PlayerShip class are worth it. Tight coupling is not evil and shouldn't be avoided at all costs—it makes sense in some contexts, and not in others. Only experience will help you figure out when to couple classes and when to decouple them.

最后,您必须确定将Bullet类与您的PlayerShip类分离的好处是否值得。紧耦合不是邪恶的,不应该不惜一切代价避免 - 它在某些情况下是有道理的,而在其他情况下则不然。只有经验才能帮助您确定何时结合课程以及何时将它们分离。

#3


The dependency injection is not suitable for this case. If you create a factory for this you will overuse design patterns. You can't decouple the entire system, in this case Ship has a composition with Bullet, and in case you need any more complex than that another pattern (not necessarily DI) might be adequate.

依赖注入不适用于这种情况。如果为此创建工厂,则会过度使用设计模式。你不能解耦整个系统,在这种情况下,Ship有一个带有Bullet的组合,如果你需要比其他更复杂的模式(不一定是DI)就足够了。

#4


Yes, this smells like over-architecting. Nevertheless, off the top of my head, you could have a property that stores the bullet Type and then have your DI framework (ninject here) create the bullet.

是的,这闻起来像是过度架构。然而,在我的脑海中,你可以拥有一个存储子弹类型的属性,然后让你的DI框架(这里是ninject)创建子弹。

public Type BulletType {get; set;}

public void fire()
{
    var b = (BulletType) kernel.get(BulletType);
    b.fire(point, direction);
}