Proper structure for dependency injection (using G

2019-07-15 07:22发布

问题:

I would like some suggestions and feedback on the best way to structure dependency injection for a system with the structure described below. I'm using Guice and thus would prefer solutions centered around it's annotation-based declarations, not XML-heavy Spring-style configuration.

Consider a set of similar objects, Ball, Box, and Tube, each dependent on a Logger, supplied via the constructor. (This might not be important, but all four classes happen to be singletons --- of the application, not Gang-of-Four, variety.)

A ToyChest class is responsible for creating and managing the three shape objects. ToyChest itself is not dependent on Logger, aside from creating the shape objects which are.

The ToyChest class is instantiated as an application singleton in a Main class.

I'm confused about the best way to construct the shapes in ToyChest. I either (1) need access to a Guice Injector instance already attached to a Module binding Logger to an implementation or (2) need to create a new Injector attached to the right Module.

(1) is accomplished by adding an @Inject Injector injectorfield to ToyChest, but this feels weird because ToyChest doesn't actually have any direct dependencies --- only those of the children it instantiates.

For (2), I'm not sure how to pass in the appropriate Module.

Am I on the right track? Is there a better way to structure this?

The answers to this question mention passing in a Provider instead of using the Injector directly, but I'm not sure how that is supposed to work.

EDIT:

Perhaps a more simple question is: when using Guice, where is the proper place to construct the shapes objects? ToyChest will do some configuration with them, but I suppose they could be constructed elsewhere. ToyChest (as the container managing them), and not Main, just seems to me like the appropriate place to construct them.

回答1:

A proper way is to have guice construct your dependencies. That is create and configure.

In your situation you should have an injector constructed in the Main. From the injector you get ToyChest. When you obtain ToyChest through the injector its managed by guice and you can depend on it to supply all dependencies properly configured.

In your case you can inject Provider<Ball>, Provider<Box>, etc. in ToyChest and when needed just retrieve instance from the provider. ToyChest is not responsible for constructing the instance, just to use it. You can also check MapBinder if you have a plugin architecture.

So far everything is managed by guice, so the shapes can have their logger injected without the using class knowing about it.

If you have some runtime parameters that you want to pass to the newly created shape instances, you can use AssistedInject.

Just a hint: you are not required to use constructor injection, you can have injection on field or setter, which simplifies the constructor.