Dagger 2 – kilka słów o (sub)komponentach

Dagger 2 – kilka słów o (sub)komponentach

Wraz z zagłębianiem się w tematykę wstrzykiwania zależności, musimy zrozumieć wiele nowych technik, które umożliwiają nam kontrolę nad tworzonymi obiektami. Dagger pozwala programiście zadeklarować interfejsy, które będą się tym zajmowały. Możemy stworzyć interfejs będący komponentem lub subkomponentem. Jaka jest różnica?

Dagger 2 – subkomponenty czy komponenty?

Jedną z pierwszych decyzji, jakie będziemy musieli podjąć podczas integracji Daggera (szczegóły jego integracji opisujemy tutaj), będzie wybór między komponentami oraz subkomponentami. Z założenia oba te komponenty mają takie samo zadanie: definiują moduły, które będą dostarczać zależności, deklarują zakres, w jakim mają one być dostępne, a także udostępniają funkcję, które umożliwią samo wstrzyknięcie zależności.

Aby przyjrzeć się różnicom, przypomnijmy sobie najpierw, jak wygląda deklaracja podstawowego komponentu:

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
}

Dany interfejs będzie traktowany przez pre-kompilator Daggera jako komponent, dzięki adnotacji @Component. Należy pamiętać, że każdy projekt musi posiadać przynajmniej jeden komponent bazowy.

Komponent

Bazowy komponent został przedstawiony w poprzednim akapicie. Deklarując kolejne komponenty nie musimy nic w nim zmieniać. Bardzo często jednak będziemy w nim tworzyć obiekty, które będą potrzebne później. Domyślnie żadne obiekty stworzone w jednym module nie są widoczne w innych. Aby udostępnić dany obiekt musimy zadeklarować w komponencie, że dany obiekt jest udostępniony. Ważny jest typ zwracany przez funkcję, a nie jej nazwa:

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
    Application application();
}

Następnie trzeba zadeklarować zależny od niego komponent pochodny:

@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {

    void inject(ComponentActivity activity);

}

Dzięki przypisaniu do zmiennej dependencies w adnotacji komponentu klasy ApplicationComponent, mamy teraz możliwość korzystania ze wszystkich udostępnionych przez niego obiektów. W naszym przypadku jest to obiekt Application.

Subkomponent

Deklaracja subkomponentów odbywa się trochę inaczej. Bazowy komponent uczestniczy w tworzeniu swoich subkomponentów. Oznacza to, że musimy go zmieniać za każdym razem, gdy dodajemy nowy subkomponent. Dzięki temu powiązaniu nie musimy się przejmować udostępnianiem obiektów komponentu bazowego. Domyślnie wszystkie obiekty tworzone w modułach bazowego komponentu są dostępne w subkomponentach. Przykładowa deklaracja komponentu wraz z subkomponentem może wyglądać następująco:

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {

    ActivitySubcomponent plus(ActivitySubModule subModule);
}
@PerActivity
@Subcomponent(modules = {ActivitySubModule.class})
public interface ActivitySubcomponent {

    void inject(SubcomponentActivity activity);
}

W Komponencie dodaliśmy metodę, która przyjmuje jako argument moduł subkomponentu oraz zwracającą sam subkomponent. W ten sposób powiedzieliśmy bazowemu komponentowi, że ma stworzyć dany subcomponent. W naszym kodzie w ten sposób będziemy pobierać instancję naszego componentu, na której będziemy mogli wykonać wstrzykiwanie. Ten sam moduł, który był argumentem funkcji w bazowym komponencie, został zadeklarowany jako moduł naszego subkomponentu. Warto zwrócić uwagę, że adnotacja @Subcomponent pozwala jedynie zadeklarować swoje moduły w odróżnieniu od @Component, gdzie była możliwość dodania zależności poprzez zmienną dependencies.

Komponenty i subkomponenty

Graf zależności w naszej aplikacji możemy budować za pomocą komponentów i subkomponentów. Dają one bardzo podobne możliwości tworzenia zarówno samych obiektów, jak i ich zakresów. Główną różnicą jest sposób przekazywania obiektów pomiędzy zależnymi modułami. Użycie komponentów daje programiście większą kontrolę nad tym, które obiekty mogą zostać wykorzystane w pochodnych komponentach.

Ważny jest także fakt, że nie musimy za każdym razem dodawać nowych funkcji do bazowego komponentu, co bardzo dobrze współgra z ideą Open-Closed. W przypadku subkomponentów od razu mamy dostęp do wszystkich obiektów z komponentu bazowego.

W naszych aplikacjach w większości przypadków lepszą praktyką będzie używanie zwykłych komponentów. Sprawi to, że nasz kod będzie czystszy i bardziej odporny na zmiany. Subkomponenty powinniśmy zostawić dla sytuacji, w których oba komponenty są ze sobą mocno powiązane logicznie i w komponencie pochodnym wykorzystane jest większość obiektów z komponentu bazowego

Dowiedz się więcej

Wycena projektu

Opowiedz nam o swoim projekcie i napisz, jak możemy Ci pomóc.

Dlaczego warto rozwijać z nami projekty?

Logo Mobile Trends Awards

Mobile Trends Awards 2021

Wygrana w kategorii
ŻYCIE CODZIENNE

Nagroda Legalnych Bukmacherów

Nagroda Legalnych Bukmacherów 2019

Najlepsza aplikacja mobilna

Mobile Trends Awards logo

Mobile Trends Awards 2023

Wygrana w kategorii
MCOMMERCE ROZWÓJ

23

opinie klientów

Clutch logo