스팀 앱 개발기 #28 - Use Case 패턴 적용
시작하며...
지난 포스트에서는 Repository 패턴을 적용하고 SteemRepository 인터페이스를 구현하면서 condenser_api.get_accounts API를 연동하는 과정을 보여 드렸습니다. 뷰 담당 모듈이 SteemRepository 구현 객체를 바로 사용하지는 않구요. Use Case 패턴 추가 적용 후에 정의할 UseCase 객체를 사용 가능하게 할 것입니다. 이게 클린 아키텍처에 의한 것이구요. 다음 포스트에서 각종 패턴들의 관계에 대해 설명을 드릴 예정입니다.
Use Case 패턴과 Repository 패턴의 관계
Use Case 객체가 Repository 객체를 참조합니다. 따라서 후자는 전자의 필드가 됩니다. 이를 코드로 나타내면 다음과 같습니다.
class ExampleUseCase(val repository: ExampleRepository) {
// ...
}
dorian-steem-domain 모듈에 ReadSteemitWalletUseCase 클래스 정의
위에 설명 드린 것을 베이스로 ReadSteemitWalletUseCase 클래스를 작성해 보겠습니다. 클래스 이름은요. SteemRepository 인터페이스에 선언된 메소드 이름을 따왔습니다. 클래스 이름만 보고도 어떤 API를 실행하고 어떤 자료를 받아오는지를 알 수 있게 하는 것입니다. 참조할 Repository 인터페이스는 이전에 정의한 SteemRepository죠. 추가할 메소드는 invoke이며, 이것은 필요한 API를 실행할 SteemRepository 인터페이스의 메소드를 호출합니다.
class ReadSteemitWalletUseCase(val steemRepository: SteemRepository) {
operator fun invoke(account: String): Flowable<Array<SteemitWalletDTO>> {
return steemRepository.readSteemitWallet(account)
}
}
참고로 invoke 메소드 선언의 맨 앞에 operator 키워드가 있죠. 이게 있으면, ReadSteemitWalletUseCase 객체의 invoke 메소드를 호출할 때 메소드 이름을 생략하고 파라메터만 사용할 수 있습니다. 예를 들면 아래와 같습니다.
val steemRepository = SteemRepositoryImpl()
val readSteemitWalletUseCase = ReadSteemitWalletUseCase(steemRepository)
// 이렇게도 호출 가능
readSteemitWalletUseCase.invoke("dorian-mobileapp")
// 요렇게도 호출 가능
readSteemitWalletUseCase("dorian-mobileapp")
ReadSteemitWalletUseCase 클래스 테스트
유닛 테스트를 이용하여 이 클래스가 잘 작동하는지 테스트할 수 있습니다. ReadSteemitWalletUseCase 클래스는 dorian-steem-domain 모듈에 속해 있지만, 테스트 클래스는 dorian-steem-data 모듈에 정의합니다. 왜냐면 ReadSteemitWalletUseCase가 참조할 SteemRepository 구현 객체가 dorian-steem-domain 모듈에 위치하기 때문입니다.
테스트 클래스 이름은 ReadSteemitWalletUseCaseTest이며, 테스트 코드는 다음과 같이 작성했습니다. SteemRepositoryTest와 비슷합니다.
class ReadSteemitWalletUseCaseTest {
val readSteemitWalletUseCase = ReadSteemitWalletUseCase(SteemRepositoryImpl())
// Test case 1: Trying to get the wallet of a valid account.
@Test
fun invoke_case1() {
readSteemitWalletUseCase(TestData.singleAccount).subscribe { wallets ->
Assert.assertEquals(1, wallets.size)
Assert.assertEquals(TestData.singleAccount, wallets[0].account)
}
}
// Test case 2: Trying to get the wallet of an invalid account.
@Test
fun invoke_case2() {
readSteemitWalletUseCase(TestData.invalidSingleAccount).subscribe { wallets ->
Assert.assertEquals(0, wallets.size)
}
}
}
테스트 결과, SteemitWalletDTO 타입의 지갑 정보를 읽을 수 있음을 확인했습니다.
GitHub Commit
마치며...
드디어 Use Case 패턴도 적용했습니다. 다음 포스트에서는 지금까지 추가한 패턴들의 역할과 관계에 대하여 간략히 정리해 보고자 합니다. 무엇을 개발하는 것도 중요하지만, '어떻게'와 '왜' 또한 중요하기 때문입니다.
지난 스팀 앱 개발기
- #27 - Repository 패턴 적용
- #26 - condenser_api.get_accounts API로 받은 계정 자료를 SteemitWalletDTO 타입으로 변환하기
- #25 - SteemClient, SteemService 잘 작동하는지 유닛 테스트
- #24 - API 실행을 담당할 SteemService 인터페이스 정의
- #23 - condenser_api.get_accounts API 연동에 필요한 데이터 클래스 정의
- #22 - API 연동에 필요한 라이브러리 추가
- #21 - 사용자 지갑 정보를 담을 SteemitWallet 클래스 정의
- #20 - 클린 아키텍처를 위한 모듈 구성 (2)
- #19 - 클린 아키텍처를 위한 모듈 구성 (1)
- #18 - VEST로부터 STEEM POWER를 계산하는 방법
- #17 - VEST를 STEEM POWER로 변환하기 위해 필요한 get_dynamic_global_properties API
- #16 - 지갑 내용을 읽기 위해 필요한 API
- #15 - 지갑 서브화면(WalletFragment) 레이아웃 구성해 보기
- #14 - 지갑 서브화면(WalletFragment)에서 계정 인식하기
- #13 - 프로파일 서브화면(ProfileFragment)에서 계정 인식하기
- #12 - 태그 서브화면에서 태그 인식하기
- #11 - 검색 레이아웃을 메인 화면에 적용
- #10 - 태그 및 계정 검색 레이아웃 만들기
- #9 - BaseActivity 클래스 정의 그리고 MainActivity 클래스에 적용
- #8 - BaseFragment 클래스 정의 그리고 기존 프래그먼트들에 적용
- #7 - ProfileFragment 그리고 WalletFragment에 데이터 바인딩 적용
- #6 - 태그별 검색 내용을 보여줄 TagsFragment에 데이터 바인딩 적용
- #5 - GitHub에 소스 올리기
- #4 - 하단 내비게이션의 탭 관련 클래스 이름 수정
- #3 - 하단 내비게이션 바의 아이콘, 텍스트 수정
- #2 - 프로젝트 생성
- #1 - 시작하며...
[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.
Upvoted! Thank you for supporting witness @jswit.