UseCase
개념
주로 생성자와 실행 함수 1개만 가진 클래스입니다.
받은 데이터에 대해 부작용(side effect)를 가하지 않는 클래스입니다.
정적 함수로 만들 수도 있지만 DI와의 궁합이 좋기 때문에 일반 클래스로 분류했습니다.
언제 UseCase를 사용하나요?
통신 처리
공통 처리로 여러 화면에서 사용되는 처리
Lifecycle로 작성하면 비대화되어 가독성이 떨어지는 경우
특히 통신처리는 여러 화면에서 호출되는 경우가 많고, 처리 내용도 비대해지기 쉽기 때문에 UseCase로 분류해서 사용합니다.
이럴 때 UseCase를 사용하도록 하세요.
예를 들어 캐릭터 정보 획득 통신은 인게임 전환 시, 편성 화면, 강화 화면 등 여러 화면에서 호출됩니다. 같은 처리를 여러곳에서 하게되므로 UseCase로 묶어 하나의 클래스로 관리하도록 합니다.
Lifecycle 대신 전부다 UseCase로 처리하면 안되나요?
통신 이외에도 모든 처리를 UseCase화 할 수도 있지만, 한 번만 사용하는 일회성 UseCase가 계속 늘어나게 됩니다. 이렇게 되면 가독성이 떨어지고 개발 효율도 떨어질 수 있습니다.
다른 공통적인 처리에서 2~3회 이상 중복 사용되는 것이 확인되면 그 때 마다 UseCase화 하여 정리하도록 하는 방식을 추구합니다.
예시 코드
아래는 통신의 UseCase 샘플입니다. 통신을 하고 결과는 받는 것 뿐만 아니라, 통신 중 UI 표시, 에러 처리 등도 포함해서 작성합니다. 사용자(Lifecycle 등)는 DoConnect를 호출하는 것만으로 오류 처리까지 포함한 통신 처리를 할 수 있습니다.
public class TestUseCase
{
private readonly IHttpClient _httpClient; // 통신 실행 클래스
private readonly NetworkErrorUseCase _networkErrorUseCase; // 통신 오류에 따른 화면 전환 등의 오류 대책
private readonly NetworkLoadingController _loadingController; // 통신 중 표시
[Inject]
public HomePageUseCase(IHttpClient httpClient, NetworkErrorUseCase networkErrorUseCase, NetworkLoadingController loadingController)
{
_httpClient = httpClient;
_networkErrorUseCase = networkErrorUseCase;
_loadingController = loadingController;
}
// DoConnect를 호출하고 실행하기
public async UniTask<TestPageLifecycle.NetworkParameter> DoConnect(CancellationToken cancellationToken) => await DoConnectInternal(cancellationToken, 0);
// DoConnect 내부 처리
// 오류 발생 시 이전까지의 재시도 횟수를 받아 재귀 처리한다.
private async UniTask<TestPageLifecycle.NetworkParameter> DoConnectInternal(CancellationToken cancellationToken, int retryCount)
{
// 통신 중... 의 UI를 표시하고 통신을 시작합니다.
_loadingController.Activate();
var connection = await _httpClient.Call<TestConnectResponse>(new TestConnectRequest(), cancellationToken);
_loadingController.InActivate();
// 실패 시 처리
if (!connection.result.IsSuccess())
{
// 예를 들어, 유지보수 중에는 유지보수 표시를 하고 제목으로 되돌립니다.
if (connection.response?.status.IsInMaintenanceMode ?? false)
{
await _networkErrorUseCase.ShowMaintenanceToTitle(connection.response?.status.error);
return null;
}
// 오류 발생 시 재시도 여부를 선택하게 한다.
// 재시도에는 최대 횟수가 설정되어 있으며, 이를 초과하면 강제로 타이틀을 되돌릴 수 있다.
var isRetry = await _networkErrorUseCase.ShowErrorWithRetry(retryCount);
if (isRetry)
{
retryCount++;
return await DoConnectInternal(cancellationToken, retryCount);
}
return null;
}
// 통신에 성공하면 응답을 반환합니다.
return new TestPageLifecycle.NetworkParameter()
{
TestConnectResponse = result.response
};
}
}
Last updated