트렌드브리프
템플릿 메서드 패턴, 알고리즘 골격을 고정하는 상속 설계

템플릿 메서드 패턴, 알고리즘 골격을 고정하는 상속 설계

· 게시 · 약 6분 분량

템플릿 메서드 패턴은 알고리즘 실행 순서를 상위 클래스에 고정하고 달라지는 단계만 하위 클래스가 구현하게 하는 GoF 행동 패턴이다. 구조와 자바 예시, 전략 패턴과의 차이, JdbcTemplate·HttpServlet 등 실무 적용과 상속 사용 시 주의점을 정리했다.

목차
  1. 어떤 문제를 푸는가
  2. 구조는 세 조각으로 나뉜다
  3. 실무에서는 어디에 쓰나
  4. 전략 패턴과 무엇이 다른가
  5. 상속을 쓸 때 주의할 점

템플릿 메서드 패턴은 알고리즘의 실행 순서를 상위 클래스 메서드 하나에 고정해 두고, 그 안에서 달라지는 일부 단계만 하위 클래스가 구현하게 하는 객체지향 설계 패턴이다. 전체 흐름의 주도권은 상위 클래스가 쥐고, 하위 클래스는 빈칸을 채우는 역할만 맡는다. 에리히 감마를 비롯한 네 저자(개발자들은 이들을 'Gang of Four', 줄여서 GoF라 부른다)가 1994년 낸 책 『Design Patterns: Elements of Reusable Object-Oriented Software』는 이 패턴을 객체 간 책임 분배를 다루는 행동 패턴으로 분류했다. 이 글은 상속을 지원하는 객체지향 언어를 전제로 패턴의 구조와 실무 쓰임을 정리하며, 코드는 자바를 기준으로 든다.

어떤 문제를 푸는가

여러 처리 과정이 큰 순서는 같은데 몇몇 단계만 다를 때가 있다. 예를 들어 CSV 파일 가져오기와 JSON 파일 가져오기는 '읽기 → 파싱 → 검증 → 저장'이라는 흐름은 똑같고, 읽는 방식과 파싱하는 방식만 갈린다. 이때 각 처리기를 통째로 복사해 두면 검증·저장 로직이 곳곳에 중복되고, 순서를 하나 고칠 때마다 모든 사본을 손봐야 한다.

템플릿 메서드 패턴은 공통 순서를 상위 클래스에 딱 한 번 정의하고, 달라지는 단계만 하위 클래스가 재정의하게 만들어 이 중복을 없앤다. 흐름의 주도권이 상위 클래스에 있다는 점이 핵심이다. 이런 구조를 '헐리우드 원칙(Hollywood Principle)'이라 부른다. '먼저 연락하지 마라, 필요하면 우리가 부르겠다'는 말처럼 하위 클래스가 상위를 호출하는 게 아니라, 상위 클래스가 하위 클래스의 메서드를 불러 쓴다. 프레임워크가 제어의 흐름을 쥐는 전형적인 모습이다.

구조는 세 조각으로 나뉜다

패턴은 세 종류의 메서드로 이뤄진다. 첫째는 템플릿 메서드다. 알고리즘의 순서를 담은 상위 클래스 메서드로, 보통 final로 선언해 하위 클래스가 순서 자체를 바꾸지 못하게 잠근다. 둘째는 추상 메서드다. 하위 클래스가 반드시 구현해야 하는 단계다. 셋째는 훅(hook) 메서드다. 상위 클래스에 기본 구현을 두되 하위 클래스가 필요할 때만 재정의하는 선택적 확장점이다.

아래는 데이터 가져오기 흐름을 템플릿 메서드로 묶은 자바 예시다. run()이 순서를 고정하는 템플릿 메서드이고, read·parse·save가 하위 클래스가 채우는 추상 단계다. validate와 shouldReindex는 기본값을 가진 훅이다.

public abstract class DataImporter {

 // 템플릿 메서드: 순서를 고정하고 재정의를 막는다
 public final void run(String path) {
  String raw = read(path);
  List<Record> records = parse(raw);
  validate(records);
  save(records);
  if (shouldReindex()) {   // 훅 메서드 호출
   reindex();
  }
 }

 protected abstract String read(String path);   // 하위 클래스 필수 구현
 protected abstract List<Record> parse(String raw);
 protected abstract void save(List<Record> records);

 protected void validate(List<Record> records) { }  // 훅: 기본은 검증 없음
 protected boolean shouldReindex() { return false; }  // 훅: 기본값 제공
 protected void reindex() { }
}

이 구조에서 CSV용 하위 클래스는 read와 parse만 CSV에 맞게 구현하면 된다. 순서를 정의한 run()은 final이라 건드릴 수 없고, 재색인이 필요한 하위 클래스만 shouldReindex()를 true로 재정의한다. 변경점은 좁게 열고 골격은 잠그는 셈이다.

고정된 단계와 점선 훅 슬롯이 섞인 골격 파이프라인에, 두 서브클래스가 각자 다른 조각으로 훅을 채우는 선화 일러스트
골격과 순서는 상위가 고정하고, 비어 있는 훅만 서브클래스가 저마다 채운다.

실무에서는 어디에 쓰나

프레임워크의 '기반 클래스'가 대부분 이 패턴이다. 뼈대는 프레임워크가 갖고, 개발자는 몇 단계만 채운다.

스프링 프레임워크의 JdbcTemplate이 대표 사례다. 스프링 공식 문서는 JdbcTemplate이 커넥션 열기·닫기와 예외 처리 같은 반복 작업을 대신 처리하고, 개발자는 콜백으로 SQL과 결과 매핑만 넘기도록 설계됐다고 설명한다. 데이터베이스 접근의 지루한 골격을 프레임워크에 맡기는 구조다.

자바 서블릿의 HttpServlet도 마찬가지다. service() 메서드가 요청 방식을 보고 doGet()이나 doPost()를 호출하는데, service()가 템플릿 메서드이고 doGet·doPost가 하위 클래스가 채우는 단계다. java.util.AbstractList는 get()과 size() 두 메서드만 구현하면 나머지 순회·검색 기능을 기본으로 내어 준다. 골격을 AbstractList가 이미 갖고 있기 때문이다.

전략 패턴과 무엇이 다른가

가장 큰 차이는 '상속이냐 위임이냐'다. 템플릿 메서드 패턴은 상속으로 일부 단계를 재정의하고, 전략(Strategy) 패턴은 알고리즘 전체를 객체로 만들어 주입한다. 둘 다 GoF 행동 패턴이지만 갈아 끼우는 방식과 시점이 다르다.

구분템플릿 메서드 패턴전략 패턴
재사용 방식상속으로 단계 재정의객체 위임(주입)
교체 시점컴파일 타임에 고정런타임에 교체 가능
바꾸는 단위알고리즘의 일부 단계알고리즘 전체

판단 기준은 단순하다. 바꾸고 싶은 게 알고리즘의 '한두 단계'이고 그 조합이 컴파일 시점에 정해진다면 템플릿 메서드가 맞다. 알고리즘 '전체'를 실행 중에 통째로 갈아 끼워야 한다면 전략 패턴이 낫다.

상속을 쓸 때 주의할 점

템플릿 메서드는 상속에 기대므로 상속의 함정도 함께 따라온다. 리팩터링 구루(Refactoring Guru)의 디자인 패턴 정리는 이 패턴을 알고리즘 골격을 상위 클래스에 두고 세부 단계만 하위 클래스가 재정의하는 것으로 요약하면서, 재정의가 상위 클래스의 계약을 어기면 골격이 무너진다는 점도 함께 짚는다. 실무에서 조심할 지점은 세 가지다.

정리하면, 템플릿 메서드 패턴은 '순서는 같고 일부만 다른' 처리들을 상속으로 묶어 중복을 줄이는 도구다. 골격은 상위 클래스에서 잠그고 변경점만 좁게 여는 원칙만 지키면, 프레임워크의 기반 클래스처럼 확장에는 열리고 수정에는 닫힌 구조를 만들 수 있다.

더 많은 글 보기 RSS 구독