简体   繁体   中英

Preventing static injection when using builder pattern

Introduction

I'm using Dagger 2 for a project that's modeled using the principles of DDD .

I'd like to use the Builder Pattern to create complex entities and the way I'd normally get an instance of the builder was by using a static factory method: ComplexEntity.builder() .

Aggregate roots will get strongly typed IDs, ie ComplexEntityID , that require a value generator for new instances. Right now I have a method for that in my module: @Provides ComplexEntityID provideComplexEntityID(IdValueGenerator generator) { return new ComplexEntityID(generator.nextId(); } .

ComplexEntityBuilder needs an instance (or provider) of ComplexEntityID in order to create a ComplexEntity . But static injection is recommended against by the people from Guice and Dagger (among others) for good reasons.

Question

How to create instances of ComplexEntity using a builder, without using static injection? In other words, how to get an instance of the builder?

Sticking to ComplexEntity.builder() would be nice because it's a common convention, but I'd think that the only way to make an instance available in a static method without using the new () keyword is by using static injection.

Another approach I could think of is to also create ComplexEntityFactory and put the builder() method there. But it seems a bit strange to use a factory and a builder together:

  1. Inject a factory in the class where you need it
  2. complexEntityFactory.builder().value1(...) .value2(...) .build();

What would be the recommended approach in this case?

Edit : If it turns out to a dedicated factory after all, tt would be nice if this factory could still be generated using AutoFactory or something similar

I think there is a more elegant solution than the one proposed by jaco0646 in the comment:

Builders are a special kind of service: You use them to realize a specific goal, but they don't have a life cycle or meaning within the domain.

So just inject builders as you would any other service.

This has several advantages:

  • Builders can use other services and factories by depending on them. In your case this is the dependency on the factory of ComplexEntityID .
  • Having a dependency on a builder is explicit (which is a good thing). At the moment, your dependency is hidden in a call to a static method.
  • You can replace the builder in tests.

Overall, this approach improves cohesion and reduces coupling.

One potential pitfall to be aware of is that builders usually have internal state (unlike typical services). So make sure to configure your dependency injection container such that a new builder instance is created for every resolve request.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM