java - sethgap - Daga 2: ¿Cuándo usar inyecciones de constructor y cuándo usar inyecciones de campo?
manager layout java (1)
Usar inyección de constructor si no puede, use la inyección de propiedad.
La regla 1 parece estar bien, al igual que las decoraciones o los atributos, puede usar la inyección de propiedad (campo).
La regla 2 parece estar bien, porque quien usa tu clase debe seguir a tu constructor. Es posible que no sepan que también deben intilizar su propiedad.
Regla 3 No solo es bueno para la prueba unitaria. Es bueno para aplicar la responsabilidad única. Es más fácil ver el gráfico de objetos. De lo contrario, lo ocultará con la propiedad.
Si llegamos a tu pregunta, sí, hay muchos parámetros en tu constructor. Pero la solución no es la inyección de propiedad . Puede refactorizar su código y usar servicios agregados
Era un poco flojo y solía usar casi por completo inyecciones de campo. Solo estaba proporcionando un constructor vacío, coloqué mis campos @Inject. Todo parecía agradable y simple. Sin embargo, la inyección de campo tiene sus compensaciones, así que he ideado algunas reglas simples que me ayudan a decidir cuándo usar el campo y cuándo usar inyecciones de constructor. Agradeceré cualquier comentario si hay un error en mi lógica o si tiene consideraciones adicionales para agregar.
Primero algunas aclaraciones para estar en la misma página:
Inyección de constructor:
@Inject
public SomeClass(@Named("app version") String appVersion,
AppPrefs appPrefs) {...
Lo mismo con la inyección de campo:
public class SomeClass {
@Inject
@Named("app version") String mAppVersion;
@Inject
AppPrefs appPrefs;
Regla 1: DEBE usar inyección de campo si no controlo la creación del objeto (piense en Actividad o Fragmento en Android). Si algún framework (que no sea para daga) está creando mi objeto y me lo maneja, no tengo más remedio que inyectarlo manualmente después de recibir la instancia.
Regla 2: DEBE usar inyección de constructor si la clase es / puede usarse en otro proyecto que no use Dagger 2 . Si los otros proyectos no usan Dagger, no pueden usar DI por lo que el usuario tiene que crear el objeto de la manera "antigua" utilizando new
.
Regla 3: PREFER la inyección del constructor cuando se trabaja con jerarquías de clases porque es más fácil crear pruebas unitarias.
Aclaración:
Teniendo en cuenta la siguiente estructura que usa inyección de campo:
package superclass;
public class SuperClass {
@Inject
HttpClient mHttpClient;
...
}
.
package differentpackage;
public class SubClass extends SuperClass {
public SubClass() {
}
}
Cuando estoy creando pruebas unitarias para SubClass
en el directorio test/java/differentpackage
no tengo más remedio que abrir toda la infraestructura DI para poder inyectar el HttpClient
. Por el contrario, si estaba usando la inyección de constructor de esta manera:
public class SuperClass {
private final HttpClient mHttpClient;
@Inject
public SuperClass(HttpClient httpClient) {
mHttpClient = httpClient;
}
}
en mi prueba de unidad pude simplemente:
HttpClient mockHttp = mock(HttpClient.class);
Subclass tested = new Subclass(mockHttp);
// tests
Así que, básicamente, ahora estoy en el otro extremo: tiendo a depender principalmente de las inyecciones de los constructores y uso las inyecciones de campo solo cuando se aplica la ''Regla 1''. El único "problema" que tengo con el constructor se inyecta es que para las clases "finales" los constructores a veces se sobrecargan bastante con los parámetros y se ven prolijos y feos como este:
@Inject
public ModelMainImpl(@Named("app version") String appVersion,
AppPrefs appPrefs,
LoginPrefs loginPrefs,
@ForApplication Context appContext,
NetworkInfoProvider networkInfoProvider,
AndroidEventPoster androidEventPoster,
Session session,
ForgeExchangeManager exchangeManager,
HttpFunctionality httpFunctionality,
@Named("base url") String baseUrl,
@Named("forge result producer") ResultProducer<ForgeExchangeResult> resultProducer
) {
Chicos, ¿cuáles son sus reglas para elegir entre inyectores de campo y constructor? Me falta algo, ¿hay errores en mi lógica?