개요 : 의존성 주입이란?
이 글은 구글 코드랩을 참조하여 작성한 글 입니다. 의존성 주입(DI;Dependency Injection)라이브러리는 제어의 역전을 활용하여 개발자가 직접 객체를 제어하는 대신 라이브러리를 통해 의존 관계를 정리해주어 느슨한 결합이 가능하게 한다. 즉 DI의 장점은 다음과 같다.
- 재사용하기 좋은 코드
- 쉬운 리팩토링
- 쉬운 테스팅
먼저 '의존성'이란 한 객체가 다른 객체에 의존한다는 것을 의미한다. 예를 들어 아래는 Car 객체가 Engine 객체에 의존하는 코드이다.
class Engine{
private int Fuel = 0
public setFuel(int Fuel){
this.Fuel=Fuel;
}
public getFuel(){
return Fuel;
}
}
class Car{
private Engine engine;
Car(){
engine = new Engine();
}
...
}
위는 Car 내부에서 Engine을 생성하기 때문에 의존성을 주입받은 것이 아닌, 의존성을 스스로 만든 결과이다.
반대로 아래는 의존성을 외부에서 주입받는 예시이다.
class Engine{
private int Fuel = 0
public setFuel(int Fuel){
this.Fuel=Fuel;
}
public getFuel(){
return Fuel;
}
}
class Car{
private Engine engine;
Car(Engine engine){
this.engine = engine();
}
...
}
engine 객체를 외부에서 주입 받음으로써 결합 관계가 약해진다. 즉, engine이 교체 되는 일이 이떠라도 Car 객체는 수정할 필요가 적어진다.
Dagger2의 핵심 구성요소
Dagger2는 크게 3가지 요소로 구성된다.
- Module: 주입할 객체 생성을 담당
- Component: Module을 지정, 로딩하여 필요한 곳에 적절히 주입한다.
- Inject: 주입 받을 객체를 가져오는 역할
가장 간단한 예시
아래는 Car객체가 Wheel, Engine객체를 통해 생성된다. MainActivity는 현재 내부에서 Car, Wheel, Engine이 생성되어 세 객체에 의존하는 상태이다.
public class MainActivity extends AppCompatActivity {
Car car;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Wheel wheel = new Wheel();
Engine engine = new Engine();
car = new Car(wheel, engine);
}
의존성 주입하기
먼저 Car 관련된 객체를 생성하는 Module 클래스를 생성해준다.
@Module
public class CarModule {
@Provides
Car provideCar(Engine engine, Wheel wheel) {
return new Car(engine, wheel);
}
@Provides
Engine provideEngine() {
return new Engine();
}
@Provides
Wheel provideWheel() {
return new Wheel();
}
}
다음으로 Module을 지정하여 실제 주입을 도와주는 인터페이스인 Component를 정의한다.
@Component(modules = CarModule.class)
public interface CarComponent {
void inject(MainActivity activity);
}
최종적으로 메인 액티비티에서 Car 객체를 @Inject로 지정하고, DaggerCarComponent의 빌더 패턴을 활용하여 CarComponent를 생성하고 해당 컴포넌트의 inject 메서드를 수행하여 최종적으로 주입한다.
참고로 위 모듈, 컴포넌트 생성 이후 프로젝트를 한번 빌드해야 아래 DaggerCarComponent가 생성된다.
public class MainActivity extends AppCompatActivity {
@Inject
Car car;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CarComponent component = DaggerCarComponent.builder()
.carModule(new CarModule())
.build();
component.inject(this);
Log.d("MyTag","Car engine : " + Car.getEngine())
}
}
추가로 위 세가지 요소 외에도 Subcomponent, Scope 등이 존재한다.
- Subcomponent: Component의 하위 계층으로, Dagger에서 그래프를 형성하게 된다. Inject를 통해 주입을 요청받으면 Subcomponent를 먼저 검색하고, 없으면 그의 부모 Component로 올라가며 검색한 뒤 주입하게 된다.
- Scope: 생성된 객체의 Lifecycle(생명주기)를 의미한다. 주로 PerActivity, PerFragment 등으로 화면의 생명주기와 동일시하며, Module에서 Scope을 보고 객체를 관리한다.
작업 흐름
Inject → Subcomponent → Module →Scope에 있을 경우 return, 없으면 생성.
못 찾았을 경우 상위 Component → Module → Scope에 있을 경우 return, 없으면 생성...
'안드로이드' 카테고리의 다른 글
[Android] 2. 구글 코드랩 Dagger를 이용한 리팩토링 - Registration Flow (0) | 2021.04.27 |
---|---|
[Android] 1. 구글 코드랩 Dagger를 이용한 리팩토링 - 개요 및 셋업 (0) | 2021.04.26 |
[Android] MVVM, RxJava, Paging 활용한 리스팅 (0) | 2021.03.11 |
[Android] Retrofit2을 활용시 반환 타입이 XML일 경우 변환 방법 (0) | 2021.03.04 |
[Android] Custom Titlebar를 fragment로 만들기 (0) | 2021.03.04 |