같은 타입의 Provider가 있을때 구분
앞서 Provider을 이용해 주입(Inject)가 되는 것을 보았다. 하지만, Provider만 사용하여 주입하는 것에는 문제점이 있다.
바로 Provider에서 제공(Provide)하는 인스턴스의 타입이 같을 때 어떤 인스턴스를 주입해야 하는지 모른다는 것이다.
예를 들어 아래와 같은 Module이 있다고 해보자.
@Module
class PersonModule {
@Provides
fun providesStudentName(): String = "StudentA"
@Provides
fun providesTeacherName(): String = "TeacherB"
}
이 모듈에서 제공하는 두가지 Provider의 반환 타입은 모두 String이다. 이 때 String 값을 아래 Student Class의 인스턴스에서 주입받고자 할 경우 어떤 Provider에서 주입 받아야 하는지 알 수 없다.
class Student() {
@Inject
lateinit var name: String
}
이를 그림으로 표현하면 다음과 같다.
Person Module 내에 같은 타입을 반환하는 Provider가 있어 주입 시 어떤 Provider을 주입시켜야 하는지 모르는 것이다.
@Named Annotation을 이용한 같은 타입 Provider 구분
이를 해결하기 위해서는 @Named Annotation을 활용한다. @Named Annotation은 같은 타입 클래스의 인스턴스를 제공하는 Provider가 두 개 이상 있을 때 그 둘을 구분해주는 역할을 한다.
제공하는 쪽(Provider)과 주입 당하는쪽(Inject) 모두에 @Named Annotation을 사용해야 구분이 되므로 둘 모두에다가 @Named Annotation을 붙여야 구분이 주입이 가능해진다.
위의 <그림1>을 <그림2>와 같이 바꾸면 Student에는 Student 이름의 주입이 가능해진다.
제공(Provider)하는 쪽의 fun과 주입받은 Student 에 모두 @Named 를 붙임으로써 Student가 어떤 Provider로부터 name 프로퍼티를 주입 받아야 하는지가 명확해졌다.
예제4에서 이에 대해 다루도록 한다. 먼저 예제4의 파일 구조는 다음과 같다.
예제 링크 : https://github.com/seyoungcho2/Dagger2Example
@Component(modules = [PersonModule::class])
interface SchoolComponent{
fun injectStudent(student: Student)
fun injectTeacher(teacher: Teacher)
}
@Module
class PersonModule {
@Provides
@Named("Student")
fun providesStudentName() = "StudentA"
@Provides
@Named("Teacher")
fun providesTeacherName() = "TeacherB"
}
PersonModule에는 두개의 프로바이더가 있으며 각각은 @Named로 구분 된다.
class Student() {
@Inject
@Named("Student")
lateinit var name: String
}
class Teacher {
@Inject
@Named("Teacher")
lateinit var name: String
}
데이터를 담는 클래스인 Student와 Teacher은 각각 var name : String을 프로퍼티로 가지고 있으며 @Named로 어떤 프로바이더에 의해 주입받아야 하는지를 명시한다.
*RunExample.kt 파일
fun main(){
val personComponent : SchoolComponent = DaggerSchoolComponent.create()
val student = Student()
personComponent.injectStudent(student)
println(student.name) // StudentA
val teacher = Teacher()
personComponent.injectTeacher(teacher)
println(teacher.name) // TeacherB
}
자 이제 Student와 Teacher의 인스턴스를 만들고 주입을 시작한다. 그러면 각각 @Named에 의해 자신이 주입 받아야 하는 인스턴스를 주입 받게 된다.
따라서 name 프로퍼티의 출력값은 Student는 StudentA가 되고 Teacher은 TeacherB가 된다.