티스토리 뷰

개요

오늘은 디자인 패턴 중에서 이름은 어렵지만 많은 곳에서 사용되는 템플릿 메서드 패턴(Template Method Pattern)에 대해 알아보도록 하겠습니다.

 

 

템플릿 메서드 패턴이란?

“템플릿 메소드 패턴은 알고리즘의 골격을 정의합니다. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스로 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 재정의할 수도 있습니다.” - 헤드 퍼스트 디자인 패턴

“템플릿 메서드 패턴은 이름 그대로 템플릿을 사용하는 방식이다. 템플릿은 기준이 되는 거대한 틀이다. 템플릿이라는 틀에 변하지 않는 부분을 몰아둔다. 그리고 일부 변하는 부분을 호출해서 해결한다.” - 스프링 핵심 원리 고급편(김영한)

 

조금 더 간단히 알아보기 위해 예시를 샌드위치로 하여 아래와 같은 절차로 만든다고 가정해보겠습니다.

  1. 빵을 준비한다.
  2. 상추와 토마토를 넣는다.
  3. ??을 넣는다.
  4. 케찹 등의 소스를 바른다.
  5. 빵으로 덮는다.

샌드위치는 1,2,4,5 번의 과정과 같이 만들기 위한 ‘기본 틀’은 정해져 있지만, 3번 과정의 ??에 어떤 재료를 넣느냐에 따라 전혀 다른 샌드위치가 만들어집니다.

이와 같이 템플릿 메서드 패턴은 기본 틀(샌드위치를 만드는 과정)을 유지하면서, 일부(재료)를 다르게 하여 다양한 결과를 만드는 방법을 말합니다.

 

 

템플릿 메서드 패턴 적용

템플릿 메서드의 주요 목적인 변하는 부분은 틀로 갖추고, 변하는 부분을 실제 코드에서 적용해보았습니다.
(적용 대상인 코드는 java로 개발한 간단한 토이 프로젝트입니다.)

 

Before

해당 코드는 간단한 자동차 경주 게임을 구현하는 코드의 일부분입니다. 콘솔을 통해 입력된 값을 개별적으로 검증하고, 입력한 값이 적절하지 않을 경우 예외 처리를 수행하며, 예외 처리 후 재입력을 받을 수 있도록 while문을 사용했습니다.

이때, 각각의 입력 값에 대한 서로 다른 검증 로직이 존재하며, 그외의 로직은 동일하여 중복이 발생한 상황입니다. 이러한 상황을 템플릿 메서드 패턴을 적용하여 관심사 분리 및 공통화를 통해 개선해 보겠습니다.

 

After

추상클래스를 통해 변하지 않는 부분에 대한 템플릿을 제공하는 public 메서드를 만들고, 변하는 검증에 대한 부분을 abstract 메서드로 제공하여 자식 클래스가 구현하도록 유도했습니다. 또한, 제네릭을 이용하여 자식클래스가 구현하는 메서드의 반환값의 다른 사항을 해결할 수 있었습니다.

 

자식 클래스는 추상 클래스를 상속받아 검증 메서드를 구현하였으며, 검증이 완료된 입력 값을 요구사항에 맞게 반환될 수 있도록 제네릭 타입으로 지정했습니다. 추가로 세부적인 예외 메세지의 경우 추상 클래스에서 protected 메서드로 선언하여 자식 클래스에서 사용하는 방식을 통해 공통화하여 처리할 수 있었습니다.

 

최종적으로 템플릿을 상속 받아 구현한 클래스를 인스턴스화하여 간편하게 검증 및 예외처리를 처리할 수 있게 되었습니다.

결과적으로 핵심 기능(입력값 검증)과 부가 기능(예외 처리 및 반복실행)을 분리하여 요구사항에 의해 입력 값이 변경되더라도 간단하게 대응할 수 있게 되었습니다. 또한, 부가기능에 대한 책임을 분리하여 관리 가능함으로 단일 책임 원칙을 지킬 수 있게되었습니다.

 

 

템플릿 메서드 패턴의 단점

템플릿 메서드 패턴은 핵심 기능과 부가 기능을 분리시키는 관심사 분리를 통해 여러가지 이점을 얻을 수 있지만 단점 또한 분명합니다.

가장 대표적인 단점으로는 “자식 클래스가 부모 클래스와 컴파일 시점에 강하게 결합되는 문제”가 있습니다. 이 부분은 조금 더 쉽게 이해할 수 있도록 다음과 같은 예시를 통해 알아보겠습니다.

 


 

모든 소비자는 온라인 쇼핑을 통해 상품을 구매시 기성품은 지마켓, 신선 식품은 마켓컬리를 통해 구매가 한다고 가정하겠습니다.

소비자는 두 쇼핑몰로 나누어 상품을 검색 후 구매해야하는 번거로움으로 인해 불편함이 많이 존재하는 상태입니다.

 

이러한 불편함은 신규 쇼핑몰 플랫폼인 쿠팡의 등장으로 간편하게 해소하게 되었습니다.
쿠팡은 쇼핑몰 플랫폼이라는 템플릿을 제공하고, 쿠팡을 이용하는 소비자는 일부 금액(구독비)을 지불하여 로켓배송 또는 로켓프레시를 입맛에 맞게 이용함으로 상품 검색과 구매에 대한 번거로움을 한 큐에 해낼 수 있게 된 것이죠.

 

우리는 이제 모든 불편함이 해결된 줄 알았습니다. 그러나 항상 장점이 있으면 단점도 존재하는 것이 세상의 이치!
쿠팡(템플릿)이 성장을 위해 새로운 기능을 추가합니다. 배달 서비스인 쿠팡 잇츠와 스트리밍 서비스인 쿠팡 플레이가 대표적이죠.

 

하지만 일부 상품 구매 및 배송 서비스만을 이용하는 저와 같은 소비자 입장에서는 필요하지 않는 기능이였죠.
또한, 이러한 기능이 추가되면서 기존 구독비를 인상까지 하여 소비자 입장에서는 불가피한 소비가 늘어나버렸습니다.
(구독비 인상에 대한 내용은 가설로 실제 사유와 일치하지 않을 수 있습니다. 이해를 위한 참고 내용으로만 봐주시길 바랍니다.)

즉, 쿠팡(부모 클래스)의 서비스(기능) 추가로 인하여 소비자(자식 클래스)는 불필요한 금액 상승(영향)이 발생하게 된 것입니다.

 

 


 

이렇듯 템플릿 메서드 패턴을 사용할 경우 부모 클래스에 기능이 추가되면 자식 클래스는 강한 결합으로 인해 기능을 사용하지 않음에도 불구하고 상속받아야 하는 상황이 발생하며, 이는 자식 클래스에 불가피한 영향을 줄 수 있다는 것을 의미합니다.

그럼으로 템플릿 메서드 패턴이 유효하게 적용되는 케이스는 부모 클래스를 상속 받는 자식 클래스가 부모 클래스의 모든 기능의 구현을 강제해야 할 경우가 적절하다 판단됩니다.

 

 

마무리

지금까지 장점과 단점이 극명하지만 많은 곳에서 사용되는 템플릿 메서드 패턴에 대해서 알아보았습니다.
본 글에서 다루었던 내용을 요약하면 아래와 같습니다.

 

1. 템플릿 메서드 패턴이란, 특정 요구사항의 기본 틀을 유지하면서 일부를 다르게 하여 다양한 결과를 만드는 방법이다.

2. 템플릿 메서드 패턴을 적용할 경우 관심사 분리를 통해 핵심 기능과 부가 기능을 분리할 수 있으며, 부가 기능에 대한 SRP를 지킬 수 있다.

3. 자식 클래스와 부모 클래스간의 강한 결합으로 부모 클래스의 변경으로 인해 자식 클래스가 불가피한 영향을 받을 수 있다.

4. 템플릿 메서드 패턴은 자식 클래스가 부모 클래스의 모든 기능에 대한 구현을 강제해야할 경우 유효하게 사용할 수 있다.

 

설명상 예시가 다소 적절하지 않을 수 있다는 생각이 듭니다. 만약, 정정이 필요하다고 판단되면 언제든지 댓글로 남겨주세요. 적극 반영하겠습니다. 지금까지 읽어주셔서 감사합니다~!

 

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday