Easy Understanding

웹 백엔드 관점으로 본 디자인 패턴 정리(9) - 템플릿 메서드 패턴(Template Method Pattern) 본문

Study

웹 백엔드 관점으로 본 디자인 패턴 정리(9) - 템플릿 메서드 패턴(Template Method Pattern)

appleg1226 2022. 5. 8. 18:11

 

- 필요 개념: 간단한 상속, 추상 클래스
- 활용도:가끔
- 난이도: 간단
- 패턴이 필요한 상황: 코드의 큰 틀만 잡아주고,세부 구현은 클라이언트에게 맡기고 싶을 때

 

코드를 작성하다보면 항상 특정 Use-Case라는 것이 존재하고, 비즈니스에서는 이게 꽤나 복잡하게 엮일 수가 있다.다음은 하나의 흐름의 예시이며, 이런 코드야 비일비재한 코드다.

1. 데이터베이스에서 불러오기
2. 데이터 가공 처리
3. 데이터 로깅
4. 데이터 변환
5. 다시 저장
6. 이벤트 발행
7. 이런 일련의 작업들을 트랜잭션 처리

 

그런데 만약 이런 로직들에 대해서 여러 구현체에서 같은 flow를 따라야 한다고 해보자.

 

비디오나 소설, 웹툰 등의 서비스를 제공하는 곳에서는 분명 종류는 다르지만 공통의 Flow로 무엇인가를 가져야 할 일들이 있을 것이다.

유저의 컨텐츠 조회 건수를 확인한다든지,

유저의 컨텐츠 구매 요청이 있다든지,

이벤트에 참여한다든지 여러 상황에서는 이런 컨텐츠들이 공통으로 묶여야 할 일이 발생하기도 한다.

 

이런 상황이 발생한다면 당연히 하나의 공통 Service로 묶고 싶은 욕심이 생길 수가 있다.

일단 여기까지는 당연히 생각해볼만한 수순이다.

public void increaseViewTime(...){
  // 1. 유저의 정보(유저 객체, 현재 접속한 기기 종류 등을 가져오기)
  // 2. 현재 열람 중인 작품 타입 및 정보
  // 3. 타입에 따라서 view time 계산 로직 적용
  // 4. 로깅
  // 5. 이벤트 발행
  // 6. 기타 등등의 처리
}

 

그렇지만 위의 메서드처럼 대부분의 구현체에서는 각자의 유스케이스를 구현하게 될 것이고, 

그러다보면 각자 필요한 방법대로 구현하게 될 것이다.

 

이걸 좀 더 공통화시키고 순서 등에 대해서 조금 더 친절하게(또는 강제로 쓰게하는) 제어할 수 있는 방식을 제공하고 싶다면, 

순서만 따로 제공하고 각 내부 알고리즘만 구현하도록 하는 방법이 있는데 그게 템플릿 메서드 패턴이다.

abstract class ViewTimeEvaluator {
  public void increaseViewTime(...){
    User user = getUserInfo(...);
    ContentDetail contentDetail = getContentDetail(...);
    ViewTime viewTime = calculateTime(user, contentDetail, ...);
    log(user, contentDetail, viewTime);
    publishEvvent(user, contentDetail, viewTime)
    ...
  }
  abstract User getUserInfo(...);
  abstract ContentDetail getContentDetail(...);
  ...
}

템플릿 메서드 패턴는 '추상 클래스'를 이용하여 구현한다.

알고리즘의 흐름만 세부 클래스로 제공하고, 실제 알고리즘은 추상 메서드로 선언해 두는 방식이다.

 

위의 컨텐츠의 예시처럼 유스케이스를 다양한 상황에 재활용하고 싶다면 템플릿 메서드 패턴을 사용하면 된다.

 

하지만, 이런 상황이 많이 발생하지는 않을 것 같고 유지보수가 오히려 복잡해질 수도 있다.

왜냐하면..

- 비즈니스 로직이 바뀌어서 한 구현체만 추가 로직이 필요한 상황이라면 어떻게 할 것인가?

- 또는 어떤 구현체만 따로 매개변수가 하나 더 필요하다면 어떻게 할 것인가?

- 만약 추가하더라도 어떤 구현체는 안쓰는 매개변수가 생길텐데 그럼 인텔리제이가 내뱉는 경고는 언제까지 버틸 수 있을 것인가?

이런 생각이 이어지다보면 패턴이 생각보다 변화에 취약하다는 생각이 많이 들 것 같다.

 

이를 위해서 Hook이라는 기법이 있어서 특정 구현체는 특정 알고리즘의 구현을 건너뛸 수 있는 방법이 있긴 하다.

하지만 이것조차 뭔가 문제를 해결하기 위한 잡기술이라는 느낌이 든다. 

애초에 잡기술이 들어갈만한 패턴이라면 한 번 더 생각을 해봐야 하지 않을까 하는 생각이다.

 

그래서 이 패턴을 사용하기 위한 전제 조건은 다음과 같다.

알고리즘 템플릿이 변화할 일이 거의 없을 것

이런 상황이 아니라면 그냥 다른 방법을 고민해서 코드를 정리해보자.