잡동사니/GPT가 알려주는

[GPT가 알려주는] 안드로이드 di, dao, model, repository

heylo 2025. 5. 20. 15:19

벡엔드에게 di (Dependency Injection) , daomodule, model, repository 설명해주려고해.

사실 나도 정확한 개념이 헷갈려. 알려줄래?

 

 

물론이죠! 😎
백엔드에게 설명하려면 Android 앱 아키텍처 관점백엔드 개발자가 이해하기 쉬운 비유를 같이 사용하는 게 효과적이에요.

 

✅ 빠르게 핵심 개념부터!

개념 한 줄 정의
Model 실제 데이터 구조 (DB 테이블 대응 클래스)
DAO DB에 접근하는 인터페이스 (insert, getAll 등 SQL 쿼리 메소드)
Repository DAO + 다른 데이터 소스(API 등)를 통합해서 뷰모델에 제공
DI (Dependency Injection) 객체를 직접 생성하지 않고, 외부에서 "주입"받는 구조
Module (Dagger/Hilt) DI가 어떤 객체를, 어떻게 만들지 정의한 "레시피"
ViewModel (참고) UI 데이터 상태를 보존하고, Repository를 통해 데이터 요청
 

 

 

 

✅ 백엔드 개발자에게 이렇게 설명해보세요:

📦 1. Model

백엔드에서 말하는 DTO나 Entity 클래스와 같아요.
예: Device(name: String, category: String)

 

 

🛠 2. DAO (Data Access Object)

DAO는 SQL을 대신해주는 DB 접근 인터페이스에요.
마치 JPA의 Repository 같은 역할.

@Dao
interface DeviceDao {
    @Query("SELECT * FROM device_table")
    fun getAll(): List<Device>
}

 

🧩 3. Repository

여러 데이터 소스(DB, API, 캐시 등)를 묶어서 ViewModel에 제공해주는 계층이에요.
백엔드의 Service Layer와 비슷합니다.

class DeviceRepository @Inject constructor(private val dao: DeviceDao) {
    fun getDevices() = dao.getAll()
}

 

💉 4. DI (Dependency Injection)

객체를 직접 생성하지 않고, 외부에서 주입 받아 사용하는 방식이에요.
Spring의 @Autowired, @Service, @Component와 같다고 보면 됩니다.

 

🔧 5. Module

Hilt나 Dagger에서는 DI에 필요한 객체 생성 방식을 정의하는 곳입니다.

@Module
@InstallIn(SingletonComponent::class)
object DaoModule {

    @Provides
    fun provideDeviceDao(db: AppDatabase): DeviceDao = db.deviceDao()
}

 

 

 

✅ 전체 흐름 예시

🔽 ViewModel
    🔽
Repository
    🔽
DAO ↔ Room DB

이 구조에서 Hilt가 각 객체를 알아서 생성하고 연결해줘서, 개발자는 그냥 @Inject만 붙이면 됩니다.

 

 

✅ 요약 키워드로 외우기

이름 역할 백엔드 비유
Model 데이터 구조 DTO / Entity
DAO DB 접근 메소드 JPA Repository
Repository 데이터 조합/가공 Service Layer
DI 의존성 주입 @Autowired
Module DI 등록소 Bean 설정

 

 

필요하시면 DI 없이 만든 코드 vs DI 사용한 코드 비교,
또는 전체 구조 그림도 그려드릴 수 있어요 😊


좋아요! 👇
"DI 없이 만든 코드 vs DI 사용한 코드" 비교
전체 구조 그림 모두 준비해드릴게요.

 

✅ 1. DI 없이 만든 코드 (직접 생성 방식, ❌비추천)

class DeviceRepository {
    private val dao = AppDatabase.getInstance().deviceDao()

    fun getDevices(): List<DeviceItem> {
        return dao.getAllDevices()
    }
}

class DeviceViewModel : ViewModel() {
    private val repository = DeviceRepository()

    fun loadDevices(): List<DeviceItem> {
        return repository.getDevices()
    }
}

 

❌ 문제점

  • DeviceRepository를 만들 때마다 내부에서 dao를 직접 생성함
  • ViewModel, Repository, DAO가 강하게 결합됨
  • 테스트/유지보수 힘듦 (모킹 불가능)

 

✅ 2. DI 사용한 코드 (Hilt 기반, 추천 ✅)

// 1. DAO 모듈에서 제공
@Module
@InstallIn(SingletonComponent::class)
object DaoModule {

    @Provides
    fun provideDeviceDao(db: AppDatabase): DeviceDao = db.deviceDao()

    @Provides
    fun provideDeviceRepository(dao: DeviceDao): DeviceRepository = DeviceRepository(dao)
}
// 2. Repository
class DeviceRepository @Inject constructor(
    private val dao: DeviceDao
) {
    fun getDevices(): List<DeviceItem> = dao.getAllDevices()
}
// 3. ViewModel
@HiltViewModel
class DeviceViewModel @Inject constructor(
    private val repository: DeviceRepository
) : ViewModel() {

    fun loadDevices(): List<DeviceItem> = repository.getDevices()
}

✅ 장점

  • ViewModel, Repository, DAO 간 결합도 낮음
  • 테스트하기 쉬움 (Mock 주입 가능)
  • 유지보수 쉬움 (Hilt가 객체 주입 관리)

 

 

 

✅ 3. 전체 구조 그림 (Hilt 기반 아키텍처)

[ View (Fragment/Activity) ]
          ↓
     ViewModel (DeviceViewModel)
          ↓
     Repository (DeviceRepository)
          ↓
         DAO (DeviceDao)
          ↓
        Room DB

[Hilt] 가 모든 걸 자동 주입해 줌

 

 

🔚 요약

비교 항목 DI 없이 DI 사용
객체 생성 직접 생성 (new) 자동 주입 (@Inject)
테스트 어려움 쉬움 (Mock 가능)
유지보수 결합도 높음 느슨한 구조
코드 재사용성 낮음 높음
의존성 관리 수동 자동 (Hilt/Dagger