쉽게 말해, 클래스가 직접 필요한 객체를 만들지 않고, 외부에서 받아오는 방식입니다.
예를 들어 커피를 만들 때 바리스타(클래스)가 직접 원두를 사고 물을 준비하는 게 아니라, 매니저(의존성 주입 시스템)가 미리 준비해 준 원두와 물을 받는다고 생각하면 됩니다.
class CoffeeMaker {
final CoffeeBeans beans = CoffeeBeans();
final Water water = Water();
void brew() {
print('커피 만들기');
}
}
위의 코드에서는 CoffeeMaker
가 원두와 물을 직접 생성하기 때문에, 만약 새로운 원두로 변경하려면 CoffeeMaker
클래스도 수정해야 합니다.
class CoffeeMaker {
final CoffeeBeans beans;
final Water water;
CoffeeMaker(this.beans, this.water);
void brew() {
print('커피 만들기');
}
}
이렇게 하면 외부에서 객체를 주입해주므로, 커피메이커는 커피 만들기에만 집중할 수 있습니다.
유지보수가 용이함
테스트가 쉬워짐
코드 재사용성이 높아짐
의존성 관리가 편리함
Flutter에서 DI를 적용할 수 있는 몇 가지 방법이 있습니다.
GetIt은 객체를 전역적으로 등록하고 필요할 때 가져다 쓰는 방법입니다.
final getIt = GetIt.instance;
void setup() {
getIt.registerSingleton<ApiService>(ApiService());
}
void main() {
setup();
runApp(MyApp());
}
class MyApp {
final apiService = getIt<ApiService>();
}
Injectable은 GetIt을 더 체계적으로 사용할 수 있도록 도와주는 패키지입니다.
class CoffeeMaker {
final CoffeeBeans beans;
CoffeeMaker(this.beans);
}
Riverpod은 상태 관리와 의존성 주입을 함께 처리할 수 있는 패키지입니다.
final coffeeProvider = Provider<CoffeeMaker>((ref) {
return CoffeeMaker(beans: CoffeeBeans());
});
Provider는 Flutter에서 기본적으로 제공하는 DI 패턴으로, 위젯 트리를 통해 의존성을 제공할 수 있습니다.
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return Provider<ApiService>(
create: (context) => ApiService(),
child: HomeScreen(),
);
}
}
GetIt
추천.Injectable + GetIt
추천.Riverpod
추천.Provider
추천.의존성 주입은 프로젝트의 유지보수성, 확장성, 테스트 용이성을 크게 향상시킬 수 있습니다.
프로젝트의 크기와 요구사항에 따라 적절한 DI 방법을 선택하는 것이 중요합니다.
chat gpt 와 구글링을 통해 정리했습니다.