기록
[GPT가 알려주는] 의존성 주입(DI: Dependency Injection)이란? 본문
🚪 1. 의존성 주입(DI: Dependency Injection)이란?
❓ 의존성이 뭐야?
- 어떤 클래스가 다른 클래스(객체)를 필요로 한다면, 그게 바로 "의존"하는 거예요.
class Car {
val engine = Engine()
}
- Car는 Engine을 직접 생성해서 사용하고 있어요.
- 이러면 나중에 Engine을 테스트용으로 바꾸거나, 다른 종류의 엔진을 넣고 싶을 때 불편해요.
✅ DI는?
- 필요한 객체(Engine)를 직접 만들지 않고, 외부에서 주입받는 방식이에요.
class Car(val engine: Engine)
이제 Car는 엔진을 받기만 해요. 만드는 책임은 외부(DI 컨테이너)가 지는 거죠.
🧠 2. 그럼 왜 필요해? 장점은?
- 테스트 편함: Mock 객체를 쉽게 넣을 수 있어요.
- 유연성 증가: 어떤 구현체를 넣을지 쉽게 바꿀 수 있어요.
- 코드 간결화: 복잡한 생성 로직을 밖으로 뺄 수 있어요.
🧰 3. Dagger는 뭔가요?
- Dagger는 **DI를 자동으로 해주는 도구(라이브러리)**예요.
- 직접 객체 만들고 연결하던 걸, Dagger가 해줘요.
- 컴파일 타임에 다 처리해서 성능이 좋아요.
🌿 4. 그럼 Hilt는 뭐야?
- Hilt는 Dagger를 쉽게 쓸 수 있게 래핑한 라이브러리예요.
- Android 전용! 라이프사이클까지 관리해줘요.
- 그냥 "Dagger의 쉬운 버전"이라고 보면 돼요.
👀 5. 코드 예시로 이해해보자
1. 주입될 객체 (예: 엔진)
class Engine @Inject constructor()
2. 의존성을 가지는 클래스 (예: 자동차)
class Car @Inject constructor(val engine: Engine)
3. Hilt Application
@HiltAndroidApp
class MyApp : Application()
4. Hilt 주입 받는 곳 (예: Activity)
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var car: Car
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// car가 자동으로 주입돼요!
}
}
💡 한 줄 요약
DI는 객체를 직접 만들지 않고 외부에서 넣어주는 방식,
Dagger는 DI를 자동으로 처리하는 도구,
Hilt는 Dagger를 Android에서 쉽게 쓰게 해주는 도구!
질문 | 답 |
DI는 객체를 parameter로 넘기는 것과 같나요? | 네, 맞습니다! 객체를 외부에서 만들어서 넘기는 개념이에요. |
그럼 DI 프레임워크는 뭘 해주는 건가요? | 그 객체를 대신 생성해서, 알아서 주입해줘요. (자동화) |
✅ 1. 테스트에서 왜 DI가 좋은가?
DI를 사용하면 클래스 안에서 직접 객체를 만들지 않고, 외부에서 주입하기 때문에,
테스트 시에 가짜(Mock) 객체를 쉽게 넣을 수 있어요.
📌 예를 들어 볼게요:
직접 생성하는 방식 (DI ❌)
class Car {
private val engine = Engine() // 테스트할 수 없음
}
- 테스트할 때, Engine을 다르게 바꿀 수 없음
- Engine이 무겁거나, 서버 통신하면 테스트 어려움
주입받는 방식 (DI ✅)
class Car(private val engine: Engine)
테스트에서는 이렇게:
val mockEngine = MockEngine()
val testCar = Car(mockEngine)
- ✅ 진짜 Engine을 안 써도 되고
- ✅ 테스트용 Engine으로 빠르게 검증 가능
- ✅ 외부 API, DB 없이 테스트 가능 (테스트가 "순수"함)
🧪 요약
항목 | 직접 생성 | DI |
테스트 유연성 | ❌ 낮음 | ✅ 높음 |
Mock 객체 사용 | ❌ 어려움 | ✅ 쉬움 |
단위 테스트 속도 | ❌ 느림 | ✅ 빠름 |
✅ 2. Hilt의 전체 구조 흐름
이제 Hilt가 어떻게 구성되고 동작하는지 전체 흐름을 그림처럼 정리해드릴게요.
🎯 Hilt 구조 요약
[ @HiltAndroidApp ]
↓
[ Application 클래스 ] ← 앱 전역 DI 컨테이너
↓
[ @AndroidEntryPoint ]
↓
[ Activity / Fragment / ViewModel ] ← 자동으로 주입받음
↓
[ @Inject constructor ] ← 생성자에 객체 주입
↓
[ @Module + @Provides / @Binds ] ← 커스터마이징 필요한 경우
🔧 주요 구성요소
구성요소 | 설명 |
@HiltAndroidApp | Hilt의 시작점. Application에 붙이면 Hilt가 앱 전체를 관리 |
@AndroidEntryPoint | 주입이 필요한 클래스(Activity 등)에 붙임 |
@Inject | 객체를 생성하고 싶을 때 사용. 생성자 주입 |
@Module | 복잡한 객체 제공할 때 수동으로 등록 |
@Provides / @Binds | 객체 생성 로직을 커스터마이징할 때 |
🧩 예제 흐름
// 1. 앱 시작
@HiltAndroidApp
class MyApp : Application()
// 2. 주입 받는 대상
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var car: Car
}
// 3. 객체 정의
class Car @Inject constructor(val engine: Engine)
// 4. 필요 시 Module 정의
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
fun provideEngine(): Engine = TurboEngine()
}
📌 Hilt는 이렇게 도와줘요
- 필요한 객체를 @Inject로 자동 생성
- Activity/Fragment/ViewModel 등에 자동 주입
- Lifecycle 따라 필요한 범위(Singleton, Activity 등)로 관리
- 테스트에서도 @TestInstallIn, @UninstallModules로 커스터마이징 가능
✅ 정리
질문 | 답 |
DI가 테스트에 왜 유리해요? | 필요한 의존성을 외부에서 주입받기 때문에, 가짜(Mock) 객체를 넣어서 빠르고 독립적인 테스트가 가능해요. |
Hilt의 구조는 어떻게 돼요? | Application → EntryPoint → Inject → Module/Provides 구조로, 전체 앱의 의존성을 자동으로 관리해줘요. |
'잡동사니 > GPT가 알려주는' 카테고리의 다른 글
[GPT가 알려주는] Smart Recomposition란? (0) | 2025.07.02 |
---|---|
[GPT가 알려주는] 리눅스의 클러스터 란? (1) | 2025.07.02 |
[GPT가 알려주는] S/W 설계 예시 (0) | 2025.07.01 |
[GPT가 알려주는] 미들웨어 (Middleware)란? (2) | 2025.06.30 |
[GPT가 알려주는] DDS (Data Distribution Service) 란? (0) | 2025.06.30 |