Byłem trochę leniwy i używałem prawie całkowicie zastrzyków polowych. Właśnie dostarczałem pustego konstruktora, umieszczałem pola @Inject, w których wszystko wyglądało ładnie i prosto. Jednak wtrysk polowy ma swoje kompromisy, więc wymyśliłem kilka prostych zasad, które pomagają mi zdecydować kiedy użyć pola i kiedy użyć zastrzyków konstruktora. Będę wdzięczny za każdą informację zwrotną, jeśli w mojej logice jest błąd lub masz dodatkowe uwagi do dodania.Sztylet 2: Kiedy używać zastrzyków konstruktorskich i kiedy używać zastrzyków polowych?
Pierwsze pewne wyjaśnienia, aby być na tej samej stronie:
wtrysk Konstruktor:
@Inject
public SomeClass(@Named("app version") String appVersion,
AppPrefs appPrefs) {...
samo z wtryskiem polu:
public class SomeClass {
@Inject
@Named("app version") String mAppVersion;
@Inject
AppPrefs appPrefs;
Zasada 1: musi użyć pola wtrysku, jeśli nie kontroluję tworzenia obiektu (pomyśl Aktywność lub Fragment w Androidzie). Jeśli jakaś struktura (nie znająca sztyletu) tworzy mój obiekt i obsługuje go, nie mam innego wyboru, jak wstrzyknąć go ręcznie po otrzymaniu instancji.
Reguła 2: MUSI używać zastrzyku konstruktora, jeśli klasa jest/może być używana w innym projekcie, który nie używa Dagger 2. Jeśli inne projekty nie używają Daggera, nie mogą używać DI, więc użytkownik musi utworzyć obiekt "w starym" stylu przy użyciu new
.
Reguła 3: PREFERUJ zastrzyk konstruktora podczas pracy z hierarchiami klas, ponieważ łatwiej jest tworzyć testy jednostkowe.
Wyjaśnienie:
Biorąc pod uwagę następujące struktury, która wykorzystuje iniekcji pola:
package superclass;
public class SuperClass {
@Inject
HttpClient mHttpClient;
...
}
.
package differentpackage;
public class SubClass extends SuperClass {
public SubClass() {
}
}
Kiedy tworzę testów jednostkowych dla SubClass
w katalogu test/java/differentpackage
mam innego wyboru, aby przywołać całą infrastrukturę DI aby móc wstrzyknąć HttpClient
. W przeciwieństwie do tego, gdybym był przy użyciu konstruktora wtrysku tak:
public class SuperClass {
private final HttpClient mHttpClient;
@Inject
public SuperClass(HttpClient httpClient) {
mHttpClient = httpClient;
}
}
w moim badanej jednostki mogłem po prostu:
HttpClient mockHttp = mock(HttpClient.class);
Subclass tested = new Subclass(mockHttp);
// tests
Więc w zasadzie teraz jestem w drugiej skrajności: staram się polegać głównie na iniekcje konstruktorów i używać zastrzyków polowych tylko wtedy, gdy ma zastosowanie "Zasada 1". Jedyny „problem”, że mam z konstruktora wstrzykuje jest to, że na zajęcia „end” konstruktorzy czasem stać się bardzo przeciążony z parametrami i wyglądają rozwlekły i brzydkie tak:
@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
) {
Guys, jakie są zasady do wybierać między konstruktorem a zastrzykami polowymi? Brakuje mi czegoś, czy są jakieś błędy w mojej logice?
https://stackoverflow.com/questions/39207845/android-dagger-2-inject-versus-provides Spójrz na to również, zapewnia dobry wgląd –