Dagger2를 알아보자 – 기본편
Dagger2를 알아보자 – Scope 
Dagger2를 알아보자 – Injection의 종류 
Dagger2를 알아보자 – Qualifier 
Dagger2를 알아보자 – Binding 
Dagger2를 알아보자 – Multibinding (You’re here)
Dagger2를 알아보자 – SubComponent
Dagger2를 알아보자 – Android
Dagger2를 알아보자 – Testing(준비중)
Dagger2를 알아보자 – Dynamic Feature에 적용하기(준비중)


Dagger를 사용하면 Multibinding(다중 바인딩)을 사용하여 여러 모듈에 객체가 바인딩되어 있어도 여러 객체를 하나의 컬렉션에 바인딩 할 수 있습니다. Dagger는 Collection을 조합하여 애플리케이션 코드가 독립적인 바인딩에 직접 의존하지 않고 의존성주입을 할 수 있도록 도와줍니다. 

Set Multibindings

여러 인스턴스를 하나의 Set으로 관리하는 멀티바인딩을 구현하기 위해서는 @IntoSet 애노테이션을 모듈내에서 사용할 수 있습니다.

메소드의 반환형이 곧 Set의 제네릭이 되며. 반환되는 객체는 오브젝트 그래프 Set<T>로 들어가게 됩니다.

@Module
public class NameModule{
    @Provides
    @IntoSet
    String provideCharles(){
        return "Charles";
    }

    @Provides
    @IntoSet
    String provideRuna(){
        return "Runa";
    }
}

@ElementsIntoSet 애노테이션을 이용하여 여러 인스턴스를 한번에 Set에 넣을 수 있습니다.

@Module
public class NameModule{
    @Provides
    @ElementsIntoSet
    Set<String> provideNames(){
        return new HashSet<String>(Arrays.asList("Charles","Runa"));
    }
}

제대로 주입이 되는지 확인해봅니다.

class Bar {
    @Inject Bar(Set<String> strings) {
        assert strings.contains("Charles");
        assert strings.contains("Runa");
    }
}

컴포넌트도 Set<String>을 제공할 수 있는지 확인해봅니다.

@Component(modules = {NameModule.class})
interface MyComponent {
  Set<String> strings();
}

@Test void testMyComponent() {
  MyComponent myComponent = DaggerMyComponent.create();
  assertThat(myComponent.strings()).containsExactly("Charles", "Runa");
}

다른 바인딩과 마찬가지로, 멀티바인딩된 Set<String>은 Provider<Set<String>> 또는 Lazy <Set<String>>에 의존성을 주입 할 수도 있습니다. 그러나 Set<Provider<Foo>>로는 의존성 주입이 불가능합니다.

Map Multibindings

Map을 이용하여 멀티바인딩을 구현할 수도 있습니다. Set Multibinding과 방법은 비슷하며, @IntoMap 애노테이션과 @MapKey 애노테이션을 이용하면 됩니다.

컴포넌트내에 인스턴스들을 Map으로 다중 바인딩하기 위해서 Module에서는 @IntoMap을 사용합니다. Map에는 Value를 관리할 Key가 필요한데, 기정의된 Key 애노테이션으로 @StringKey, @IntLong, @LongKey, @ClassKey 등이 있습니다.

다음과 같이 Module에서 컴포넌트에 멀티바인딩 객체를 제공할 수 있습니다.

@Module
class MyModule {
    @Provides 
    @IntoMap
    @StringKey("foo")
    static Long provideFooValue() {
        return 100L;
    }

    @Provides 
    @IntoMap
    @ClassKey(Thing.class)
    static String provideThingValue() {
        return "value for Thing";
    }
}

컴포넌트를 통해 Map이 제대로 제공 되는지 확인합니다.

@Component(modules = MyModule.class)
interface MyComponent {
    Map<String, Long> longsByString();
    Map<Class<?>, String> stringsByClass();
}

@Test void testMyComponent() {
    MyComponent myComponent = DaggerMyComponent.create();
    assertThat(myComponent.longsByString().get("foo")).isEqualTo(100L);
    assertThat(myComponent.stringsByClass().get(Thing.class))
        .isEqualTo("value for Thing");
}

@Multibinds

컴포넌트 내에서 이미 제공된 Set이나 Map 이 있다면 모듈의 abstract 메소드에 @Multibinds 애노테이션을 추가해서 멀티바인딩을 구현할 수 있습니다. 최소한 하나이상 @IntoSet, @ElementsIntoSet 또는 @IntoMap을 갖는 Set 이나 Map을 위해서는 이 애노테이션을 추가할 필요는 없지만, 만약 Map 또는 Set이 비어있을수 있다면 사용하면 됩니다.

@Module
abstract class MyModule {
    @Multibinds abstract Set<Foo> aSet();
    @Multibinds @MyQualifier abstract Set<Foo> aQualifiedSet();
    @Multibinds abstract Map<String, Foo> aMap();
    @Multibinds @MyQualifier abstract Map<String, Foo> aQualifiedMap();
}
Buy me a coffeeBuy me a coffee

0개의 댓글

답글 남기기

이메일은 공개되지 않습니다.