Isn't Google Guice just another Factory?

I want to create an instance of a user account. I can use factory, for example:

public class UserFactory { public User newUser(UserType type) { if (type == UserType.FREE) return new FreeUser(); } } User user = UserFactory.newUser(UserType.FREE); //UserType.FREE is an enum 

Now, if I use Google Guice, I have to write a β€œmodule”:

 public class UserModule extends AbstractModule { public voidSetType(UserType type) { this.type = type; } @Override protected void configure() { if (this.type = UserType.FREE) bind(User.class).to(FreeUser.class); else bind ..... } } 

Then this is the client code:

 Injector injector = Guice.createInjector(new UserModule().setType(UserType.FREE))); 

My question is: Instead of writing a factory class, I should write a module class. And from the above example, I see no advantage. The module class uses reflection, it is slower than my assignment operator in the factory class. A module class is no simpler than a factory class. Instead of supporting the factory, I should support the module.

What is the real advantage? Isn't Google Guice just a factory class?

+7
source share
3 answers

You do not see the benefits, since Guice ( Injection Dependency ) is not intended to replace plants . This can be done to a limited extent (see AssistedInject and Providers), but if you have logic in the factory, then it is unlikely that you can use Guice as a direct replacement.

For Guice, it would still have a factory for this, and Guice introduces a factory. Now the user sounds like a domain object, and most likely, the dependency tree embedded in Guice is not required. If so, then the factory should be a Guice warning and either accept a Provider for each type of user, or have direct access to Inject to create user objects using different Keys.

DIs are all dependency trees. Factories are all about creating objects without calling the caller to take care of how this object is implemented. They intersect and can be used together, but they solve different problems.

+8
source

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.

+2
source

Do you really need a "UserType"?

consider this:

 class FreeUser extends User {...} class NonFreeUser extends User {...} void configure() { // if Type=Free bind(User.class).annotatedWith(Free.class).to(FreeUser.class); // else bind(User.class).to(NonFreeUser.class) } 

and then

 class SomeClassThatNeedsAFreeUser { @Inject @Free private User user; } 

so when you use injector.getInstance (SomeClassThatNeedsAFreeUser.class), you will get an instance into which FreeSUer is automatically entered ... I think this is a much better approach than a hard link through certain factories.

0
source

All Articles