오늘도 더 나은 코드를 작성하였습니까?

DomainLayer(usecase) 사용하기 본문

Android Jetpack Architecture

DomainLayer(usecase) 사용하기

hik14 2022. 5. 10. 21:09

원칙

-  관심사의 분리(컴퓨터 공학 디자인 원칙, 계층화된 디자인)

구별된 부분으로 분리시키는 디자인 원칙으로, 각 부문은 개개의 관심사를 해결

 

-  단일 책임의 원칙(객체지향 프로그래밍의 원칙)

클래스  변경하려는 단 하나 이유만을 가져야 한다고 결론 

 

- Data Model에서 UI 도출

 데이터 모델(UI 요소 및 기타 구성요소와 독립적)에서 UI를 도출해야 한다는 것

 

구조화 계층

UI  Layer (표현 계층)

화면에 애플리케이션 데이터를 표시하는 것.

사용자 상호작용(예: 버튼 누르기) 또는 외부 입력(예: 네트워크 응답)으로 인해 데이터가 변할 때마다 변경사항을 반영하도록 UI가 업데이트된다

UI elements 

 화면에 데이터를 렌더링하는 UI 요소. 이러한 요소는 View(xml) 또는 Jetpack Compose 함수를 사용하여 Activity/Fragment에 빌드

State Holders

 데이터를 보유하고 이를 UI에 노출하며 로직을 처리하는 상태 홀더(ViewModel)

 

 UI controller(Activity, Fragment) 와 ViewModel (N : N)

* viewModel의 생명주기를 잘 설정해야 한다.

Data Layer(데이터 계층)

데이터 레이어에는 비즈니스 로직이 포함

비즈니스 로직은 앱에 가치를 부여하는 요소 -  (앱의 데이터 생성, 저장, 변경 방식을 결정하는 규칙으로 구성)

 

*Repository Pattern - 데이터 소스(로컬 DB, Network API, )와 관계 없이 동일한 인터페이스로 데이터 제공 및 접근

 

- 앱에서 처리하는 다양한 유형의 데이터마다 저장소 클래스를 만들어야 한다.

- 각 저장소는 0-N개의 데이터 소스를 포함 할수 있다.

 

ViewModel - Repository (N : N)

* Repository는 Singleton 객체, 하나의 데이터 소스 를 관리한다. 

 

 

Android MVVM 기본적인 구조

 

 

Domain Layer(도메인 계층)

domain - 데이터를 다루는 영역, 범위

 

domain는 UI 레이어와 data layer 사이에 존재 선택적이다.

복잡한 비즈니스 로직, 또는 여러 ViewModel에서 재사용되는 간단한 비즈니스 로직의 캡슐화를 담당

복잡성을 처리하거나 재사용성을 선호하는 등 필요한 경우에만 도메인 레이어를 사용

  • 코드 중복을 방지
  • domain layer 를 사용하는 클래스의 가독성을 개선
  • 앱의 테스트 가능성을 높입니다.
  • 책임을 분할하여 대형 클래스를 방지

 

UseCase

 

 

현재 시제의 동사 + 명사/대상(선택사항) + UseCase

class GetLatestNewsWithAuthorsUseCase(
  private val newsRepository: NewsRepository,
  private val authorsRepository: AuthorsRepository
) { /* ... */ }
class GetLatestNewsWithAuthorsUseCase(
  private val newsRepository: NewsRepository,
  private val authorsRepository: AuthorsRepository,
  private val formatDateUseCase: FormatDateUseCase
) { /* ... */ }
class FormatDateUseCase(userRepository: UserRepository) {

    private val formatter = SimpleDateFormat(
        userRepository.getPreferredDateFormat(),
        userRepository.getPreferredLocale()
    )

    operator fun invoke(date: Date): String {
        return formatter.format(date)
    }
}

Life Cycle

UseCase 고유한 수명 주기를 갖지는 않습니다. UseCase 를 사용하는 클래스로 범위가 지정됩니다.

즉, UI 레이어의 클래스에서, 서비스에서 또는 Application 클래스 자체에서 사용 사례를 호출할 수 있습니다.

UseCase는 변경 가능한 데이터를 포함해서는 안 되므로 개발자가 UseCase 클래스의 새 인스턴스를 종속 항목으로 전달할 때마다 그 인스턴스를 생성해야된다.

 

Threading

도메인 레이어의 UseCase 기본 안전성을 갖추어야 합니다. 즉, MainThread 에서 안전하게 호출되어야 합니다.

 

UseCase 클래스는 장기 실행 차단 작업을 실행하는 경우 관련 로직을 적절한 스레드로 옮깁니다.

하지만, 그 작업 전에 개발자는 계층 구조에서 Thread 차단 작업이 더 잘 배치되는 다른 레이어가 있는지 확인하여 배치한다. 

 

복잡한 계산은 재사용이나 캐싱을 유도하기 위해 데이터 레이어에서 이루어집니다.

 

예를 들어 결과를 캐시하여 앱의 여러 화면에서 재사용해야 하는 경우 대용량 목록을 대상으로 한 리소스 집약적인 작업은 도메인 레이어보다 데이터 레이어에 더 잘 배치됩니다

class MyUseCase(
    private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {

    suspend operator fun invoke(...) = withContext(defaultDispatcher) {
        // Long-running blocking operations happen on a background thread.
    }
}

 

Repository 결합.

 

뉴스와 작성자 데이터 작업을 각각 처리하는 NewsRepository 클래스와 AuthorsRepository.

 NewsRepository에서 제공하는 Article 클래스에는  Authors 이름만 알수있다.

개발자는 화면에 자세한 작성자 정보를 표시하고자 할 수 있습니다. 작성자 정보는 AuthorsRepository에서 얻어야 한다.