Guice is clearly not just a factory. It is intended to reduce the scheme of building collaborators in the system and to share responsibility for creating the dependencies of these employees. Reasons for this include:
- Reduced template code (if you do it right)
- Dependencies are abstracted and therefore can be replaced by:
- testing time - the implementation of fake / mock / stub can be replaced by
- runtime - alternative implementations can be replaced when functions change.
- Design principles such as Separation of Interface and Single Responsibility
As another answer said, there is a crossover between dependency injection and factories - they are both related to managed objects and have their dependencies satisfied by an external system, but they work differently. In this case, you will need a factory. But with Dependency-Injection, if you have many factories that require each other to work properly, you can have a dependency injection infrastructure like Guice, manage plant interdependence without a lot of manual wiring code and another template.
I tend to break down which dependencies exist in several different types, and consider injection only for some types.
+ ======================= = ========================== === + ===================== +
| Type | Note | Inject? |
+ ======================= = ========================== === + ===================== +
| Static Dependencies | Inherited types | N / A |
+ ---------------------- + -------------------------- --- + -------------------- +
| Collaborators | Services, Factories, etc. | Definitely |
+ ---------------------- + -------------------------- --- + -------------------- +
| Configuration | Context | Maybe - be careful |
+ ---------------------- + -------------------------- --- + -------------------- +
| Consumables / Data | Value types | No - use factories |
+ ======================= = ========================== === + ===================== +
Of course, no rules are hard and fast, but, generally speaking, I try not to introduce value types unless they are used invariably as a context for the entire area of ββdependent objects.
Thus, using a user type as a context, say, for a query, is fine, but only if it is immutable and provided as a "global context" for all objects whose scope is that request. But if I intend to work with this user, I will manage it with the plants, possibly in another separate workflow / request.
Automatic dependency injection is great for managing collaborators, services, and service classes β large parts of your application. Of course, you can bring it to the micro level, but you need to be careful not to go too crazy, or be aware of compromises in complexity. Yes, your code will become more general and more reusable and abstract - but the effects will have less obvious reasons (the error can now be the result of initialization much earlier in the current system), your flow will be less linear, and your code may seem more magical.
If you find that you are writing more module code than you save from manual wiring, review your project again.
Side notes: 1. You can get Guice and Dependency-Injection schemas by refactoring factories and wire code to the extreme, but factories are specifically designed to manage specific classes β Guice is generic by definition, so it is not suitable for replacing some types of factories. Clean factories, perhaps. 2. You can enter value types by injection, but you run into difficulties - value types (domain objects) may require dependency cycles legally, which Guice and others are not intended for, although they support it. You play with fire, but in a system where everyone understands style and approach, it can be strong. Use with extreme caution.