템플릿 메서드 패턴은 전략 패턴만큼 잘 알려져 있고 자주 사용되는 디자인 패턴의 간판 얼굴인 것 같다.
미리 처리 플로우를 정해 두고 그거에 맞춰서 코딩하게 강제할 수 있기 때문에 SI 에서 사랑받을 것 같은 패턴이다.
예를 들어 컨트롤러가 해야 할 입력값 검증, 비지니스 로직 호출, 응답이라는 일련의 플로우를
템플릿 메서드를 활용해서 추상 클래스로 만들고 그 추상 클래스를 확장하게 할 수 있다.
Template Method Pattern
로직을 처리하기 위해 필요한 방법들은 서브 클래스에서 구현하게 추상 메서드로 만들고
그 추상 메서드들을 조합해서 일련의 처리 과정, 알고리즘을 템플릿 메서드로 정의하는 것이 템플릿 메서드 패턴이다.
템플릿의 사전적 의미인 "어떤 것을 만들 때 안내 역할을 하는, 사용상의 형식" 에 딱 들어맞는 패턴이다.
템플릿 메서드가 정의되어 있는 추상 클래스는 고수준 클래스로 어떠한 로직 처리를 실제로 담당하고 있고
추상 클래스를 확장하여 구현하고 있는 서브클래스는 템플릿 메서드에 필요한 처리 메서드를 구현하는데,
추상 클래스의 템플릿 메서드가 클라이언트에게 호출되기 전까지 서브클래스의 메서드들은 호출되지 않는다.
즉 클라이언트는 추상 클래스의 템플릿 메서드 하나에 의존하면 되기 때문에 의존성 결합이 느슨해지는 효과가 있다.
템플릿 메서드 패턴을 구성하고 있는 요소들을 정리해 보면 아래와 같이 세 가지 요소가 있다.
- 어떠한 요청의 처리의 플로우, 알고리즘을 정의하고 있는 템플릿 메서드
- 템플릿 메서드 내에서 사용되며 서브클래스가 구현해야 하는 추상 메서드
- 템플릿 메서드 내에서 사용되며 추상 클래스에서 어떤 코드도 들어 있지 않거나 기본적인 구현을 해 두고,
서브클래스가 선택적으로 오버라이딩 해서 사용할 수 있는 메서드
→ 책에서는 Hook 라고 부르고 있음
Template Method Pattern 구현
템플릿 메서드 패턴과 궁합이 좋은 것이 제네릭이다.
템플릿 메서드에 사용할 입력 객체, 출력 객체를 제네릭을 사용해서 제한할 수 있다.
Post 요청을 처리하는 컨트롤러에 필요한 요청, 응답, Dto 를 제네릭으로 정의하였다.
요청은 RequestBody 인터페이스를 확장한 타입의 객체만 허락하고
응답은 RespnseBody 인터페이스를 확장한 타입의 객체만 허락하고
Dto 는 모든 객체를 허락한 any 타입이다.
Post 요청을 처리하는 일련의 처리 과정을 정의한 템플릿 메서드인 execute 메서드는
요청을 검증하는 checkRequest 메서드
요청 객체를 Dto 로 매핑하는 mapToDto 메서드
비지니스 로직을 처리하는 doService 메서드
응답 객체를 생성하는 createResponse 메서드로 이루어져 있고,
각 처리 과정에서 에러가 발생하면 캐치해서 에러 유형에 맞춰서 처리하고 있다.
public abstract class BasePostController<RQ extends RequestBody, RS extends ResponseBody, Dto> {
public final Response<?> execute(RQ requestBody) {
try {
checkRequest(requestBody);
return createResponse(doService(mapToDto(requestBody)));
} catch (BadRequestException e) {
return createErrorResponse(e.getMessage(), 400);
} catch (ApplicationException e) {
return createErrorResponse(e.getMessage(), e.getStatus());
} catch (Exception e) {
return createErrorResponse(e.getMessage(), 500);
}
}
템플릿 메서드에서 사용되는 메서드는 다음과 같다.
checkRequest 메서드는 후크로 요청을 검증할지 말지는 서브 클래스에서 맡기고 어떤 코드도 작성되어 있지 않다.
나머지 메서드들은 서브클래스에서 구현해야 하는 추상 메서드이다.
protected void checkRequest(RQ requestBody) {
}
protected abstract Dto mapToDto(RQ requestBody);
protected abstract RS doService(Dto dto);
protected abstract Response<RS> createResponse(RS responseBody);
private Response<ErrorResponse> createErrorResponse(String message, int status) {
return new Response<>(new ErrorResponse(message), status);
}
전체 소스는 https://github.com/Jongwon-Hyun/design_pattern
그리고 이번에 자바 레코드 써봤는데 괜찮은 것 같다. 진작에 나왔어야지! 자바 진영의 속도란.. 하아..
그리고 고에는 제네릭을 써봤는데 깐깐한 타입체크 때문에 사용하기 쉽지는 않은 것 같다.
형변환과 필드설정이라는 꼼수로 억지로 만들었다는 느낌을 지울 수 없는데
아마 고에서는 이렇게 코딩하면 안 될 것 같다.
'Programming > OOP' 카테고리의 다른 글
[Design Pattern] Facade Pattern, 파사드 패턴 (0) | 2022.05.16 |
---|---|
[Design Pattern] Adapter Pattern, 어댑터패턴 (0) | 2022.05.09 |
[Design Pattern] Command Pattern, 커맨드 패턴 (2) | 2022.05.06 |
[Design Pattern] Singleton Pattern, 싱글톤 패턴 (0) | 2022.05.02 |
[Design Pattern] Abstract Factory Pattern, 추상 팩토리 패턴 (0) | 2022.04.29 |
댓글