13. 컴포넌트 간의 의존 관계
- 다수의 컴포넌트를 생성 및 상호 의존 관계를 맺을 수도 있음
- 방법
- 서브 컴포넌트
- 컴포넌트 상속
서브 컴포넌트
- 서브 컴포넌트 내에 다른 서브컴포넌트 구현
- 두 컴포넌트를 연관 짓는 쉬운 방법
- 서브 컴포넌트는 상위 컴포넌트에 바인딩된 모든 의존성을 제공 받음 (그 반대는 불가)
- SubComponentB 는 SubComponentA, Component가 가진 모듈로 부터 의존성을 제공 받을 수 있음
- SubComponentA 는 Component 모듈로 부터 의존성을 제공 받을 수 있음
- Component 는 하위 컴포넌트 들이 가진 의존성을 제공 받을 수 없음 ❌
서브 컴포넌트의 정의
- 추상 클래스 또는 인터페이스에
@Component
대신@Subcomponent
어노테이션을 붙임 @Subcomponent
속성 modules에 바인딩 하려는 모듈 클래스들을 추가- 서브 컴포넌트를 만들려면 빌더 또는 팩토리를 반드시 정의 할것.
예제
- 카페에가면.. 커피. 커피를 만들려면.. 에스프레소 머신(커피콩 + 물)
- 카페 = 컴포넌트
- 에스프레소 머신 = 서브 컴포넌트
import dagger.Subcomponent
@Subcomponent(modules = [MachineModule::class])
interface MachineComponent {
fun getCoffee():Coffee
fun inject(machine: Machine)
@Subcomponent.Builder
interface Builder{
fun setMachineModule(coffeeMachineModule: MachineModule):Builder
fun build():MachineComponent
}
}
class Machine {
private lateinit var component: MachineComponent
constructor(builder: MachineComponent.Builder){ // 매개변수로 서브 컴포넌트로부터 빌더를 제공 받음
component = builder.setMachineModule(MachineModule())
.build()
component.inject(this)
}
fun extract() = component.getCoffee()
}
import dagger.Module
import dagger.Provides
@Module
class MachineModule {
@Provides
fun provideCoffeeBean() = CoffeeBean()
}
import javax.inject.Inject
class Coffee @Inject constructor(coffeeBean: CoffeeBean, water: Water) {
}
class CoffeeBean {
}
class Water {
}
서브 컴포넌트 추가
- 서브 컴포넌트(MachineComponent)를 정의 했고
- 이제 컴포넌트에 서브 컴포넌트로 추가 해야함
- 컴포넌트가 가진
@Module
의 멤버인 subcomponent에 서브 컴포넌트 클래스를 추가 - 서브 컴포넌트가 연결됬다면, 연결된 컴포넌트 모듈로부터 서브 컴포넌트의 빌더를 요청할 수 있음
import javax.inject.Inject
class Cafe {
@Inject
lateinit var coffeeMachine: Machine
init{
DaggerCafeComponent.create().inject(this)
}
fun orderCoffee() = coffeeMachine.extract()
}
import dagger.Component
@Component(modules = [CafeModule::class]) // CafeModule로부터 Machine을 제공 받음
interface CafeComponent {
fun inject(cafe: Cafe)
}
import dagger.Module
import dagger.Provides
@Module(subcomponents = [MachineComponent::class])
class CafeModule {
@Provides
fun provideWater() = Water()
@Provides
fun provideMachine(builder: MachineComponent.Builder) = Machine(builder)
}
커피 주문 테스트 코드
반응형
class CoffeeUnitTest {
@Test
fun test_cafe(){
val cafe = Cafe()
println(cafe.orderCoffee())
println(cafe.orderCoffee())
println(cafe.orderCoffee())
}
}
com.lilcode.hellodagger.subComponent.Coffee@72a9989
com.lilcode.hellodagger.subComponent.Coffee@4a0fd396
com.lilcode.hellodagger.subComponent.Coffee@32cd3972
서브 컴포넌트의 특징
- 머신-component 는 카페-component의 일부분
- 머신-component는 카페-component 가 가진 카페-module 로부터 모듈이 가진 의존성을 제공 받을 수 있음
- 하지만, 카페-component는 머신-component.builder를 제외하고는 서브 컴포넌트가 가진 모듈의 의존성을 제공 받을 수 없음.
- 서브 컴포넌트는 독립적인 생명주기를 가짐
- 컴포넌트가 존재하는 동안 서브 컴포넌트는 생성과 소멸을 반복할 수 있음.
- 컴포넌트 소멸시 서브 컴포넌트도 같이 소멸
컴포넌트의 상속
- 오브젝트 그래프 내의 하위 그래프를 작성하는 게 가장 간단하지만,
- 서브 컴포넌트는 부모 컴포넌트와 밀접하여 분리가 어려움
- 그 대안으로 컴포넌트의 상속이 있음
@Component
의dependencies
속성에 상속 컴포넌트 클래스를 추가- 상속한 컴포넌트의 의존성 사용을 위해 상속한 컴포넌트는 해당 의존성을 프로비전 메서드로 제공해야함
그럼 예시를 구현해보자
[ComponentA]
import dagger.Component
@Component(modules = [ModuleA::class])
interface ComponentA {
fun provideString(): String // 프로비전 메서드
}
[ModuleA]
import dagger.Module
import dagger.Provides
@Module
class ModuleA {
@Provides
fun provideString() = "String from ModuleA"
}
[ComponentB]
import dagger.Component
@Component(
modules = [ModuleB::class],
dependencies = [ComponentA::class]
)
interface ComponentB {
fun inject(foo: Foo)
}
[ModuleB]
import dagger.Module
import dagger.Provides
@Module
class ModuleB {
@Provides
fun provideInteger() = 100
}
[Foo]
import javax.inject.Inject
import javax.inject.Named
class Foo {
@Inject
lateinit var str: String
@set: [Inject Named("int")]
var int: Int? = null
}
테스트
import org.junit.Test
class SubComponentInheritanceTest {
@Test
fun test_subComponentInheritance(){
val foo = Foo()
val componentA = DaggerComponentA.create()
val componentB = DaggerComponentB.builder()
.componentA(componentA)
.build()
componentB.inject(foo)
println(foo.str) // String from ModuleA
println(foo.int) // 100
}
}
컴포넌트B
가컴포넌트A
를 상속하여컴포넌트A
의 프로비전 메서드로 부터 String 타입 의존성을 제공 받을 수 있음
2021.07.27 - [Android/클린 아키텍처] - [Clean Architecture] 13-Dagger 멀티 바인딩 하기
2021.07.26 - [Android/클린 아키텍처] - [Clean Architecture] 12-바인딩의 종류 (Dagger)
2021.07.25 - [Android/클린 아키텍처] - [Clean Architecture] 11-범위 지정하기 (@Scope)
해당 글은 '아키텍처를 알아야 앱 개발이 보인다' 를 공부하며 요약 정리한 글 입니다.
'Android > 클린 아키텍처' 카테고리의 다른 글
[Clean Architecture] 15-안드로이드에서의 Dagger2 (0) | 2021.08.04 |
---|---|
[Clean Architecture] 13-Dagger 멀티 바인딩 하기 (0) | 2021.07.27 |
[Clean Architecture] 12-바인딩의 종류 (Dagger) (0) | 2021.07.26 |
[Clean Architecture] 11-범위 지정하기 (@Scope) (0) | 2021.07.25 |
[Clean Architecture] 10-한정자 (@named) (0) | 2021.07.24 |