DI(dependency Injection)를 이용한 빈 의존성 관리
모듈간의 연결로, A클래스가 객체를 만들기 위해 B를 필요로 할 때, B는 A의 의존(Dependency)의 대상이 된다.
class Car {
Tire mTire;
Car(int tireSize){
mTire = new Tire(tireSize);
}
void drive(){
}
}
예) 현대자동차에서 타이어를 만들지 않는다. 금호타이어같은 회사에 주문해서 받아와 조립할 뿐
즉, Car 내부에서 Tire객체를 만드는 것이 아니라, 외부에서 Tire객체를 만들어 받아와서 Car 클래스를 생성하도록 한다.
이렇게 외부에서 의존관계가 있는 대상을 가져오는 것을 Dependency를 외부에서 Inject해 준다고 한다.
(내부에 변수로 다른 Class를 사용)
class Main{
public static void main(String[] args){
Tire mTire = new Tire(88); //생성자 주입
Car mCar = new Car(mTire);
mCar.drive();
mCar.mEngine = new Engine(); // 필드주입
mCar.start();
}
class Car {
Tire mTire;
Engine mEngine;
Car(Tire tire){
mTire = tire;
}
void drive(){
}
void start(){
mEngine.start();
}
}
라이브러리를 사용하는 이유
자동차에는 엄청나게 많은 부품이 들어간다. 이를 클래스로 만들면 Car class에 많은 부품을 객체로 받아들일 수 있는 생성자나 setter메소드가 필요하다.
그럼 그에 따라 생성자나 setter메소드를 모두 관리해 주어야 한다.이러한 부분에서 효율성을 높이기 위해, 올바른 순서로 생성시키고 객체를 받아들일 수 있도록 관리하는 라이브러리를 사용한다.
🙋♀️ DI는 어떤 디자인 패턴을 사용할까?
전략패턴 참고
장점 : 의존하고 있는 클래스가 변경되더라도 인터페이스를 통해서 의존하고 있기 대문에, B클래스를 바꾸고 싶다면 의존설정 시 에 다른 클래스만 명시하면 된다.
이렇게 설정을 하면 OCP와 DIP를 자연스럽게 따르게 된다.
🙋♀️ DI의 개념에서의 DIP(Dependency Inversion Principle)
- DI + 인터페이스(추상화)
- 인터페이스(추상화)에서는 의존성 정보를 갖고 있으면 안된다.
- 구체적인 의존관계가 추상화에 의해 런타임에 결정되기 대문에 다형성을 적극적으로 활용할 수 있으며 모듈의 재사용성, 테스트용이성이 높아진다.
🙋♀️ IoC를 사용했을때 vs 안했을때
(아직 미흡)= IoC(제어역전)를 구현하는 기술들
1. 팩토리 패턴 사용
2. 서비스 로케이터 패턴 사용 : 의존성이 필요한 시점에 service locator에 요청
3. DI사용 : 생성자주입, 변수주입, 인터페이스주입
Annotaion Processing을 통한 코드생성
Reflection을 사용하지 않기에 Dagger보다 가볍다.
Activity에서만 Inject할 수 있다.
다른 class type에서 inject하려면 관련된 constructor를 반드시 제공해야 한다.
(->Koincomponent로 해결가능)
🙋♀️ Single로는 동일 타입의 Instance는 한번 만 만들 수 있을까?
동일타입의 Instance가 여러개 필요하다면 qualifier를 지정하여 만들 수 있다.
single(named("first")){MyClass()} single(named("second")){MyClass()} val first : MyClass = get(named("first")) val second : MyClass = get(named("second"))
👀 Koin vs Dagger2
1. Koin
- 모듈에서 선언한 DI를 Cache에 저장하고 있다.
- 처음 앱을 구동할 때 한번 캐싱한다.
- Injection대상필드가 주입하기 위해 객체를 가져오는 Pull방식(private 접근)