티스토리 뷰

템플릿 메소드 패턴이란?

템플릿 메소드 패턴은 여러 클래스에서 공통으로 사용하는 메서드를 템플릿화 하여 상위 클래스에서 정의하고, 하위 클래스마다 세부 동작 사항을 다르게 구현하는 패턴이다. 즉, 변하지 않는 기능(템플릿)은 상위 클래스에 만들어두고 자주 변경되며 확장할 기능은 하위 클래스에서 만들도록 하여, 코드의 중복을 막고 하위 클래스에서 확장을 제어할 수 있도록 한다. 

템플릿 메소드 패턴 사용 법

  • Template(추상 클래스)
    • 하위 클래스에서 구현해야 할 추상 primitive 오퍼레이션들을 정의
    • 알고리즘의 기본 골격을 구성하는 템플릿 메소드를 구현
  • ConcreteClass(구현 클래스)
    • 템플릿 메소드에서 이용될 primitive operation들을 구현

-> ConcreteClass는 변동되는 부분을 구현하고 알고리즘에서 변하지 않는 부분은 AbstractClass에 구현을 맡긴다.

 

템플릿 메소드는 코드 재사용을 위한 기본적인 방법이다.
일반적인 상속의 경우 하위클래스가 상위클래스의 함수를 호출하는데 반하여, 템플릿 메소드 패턴에서는 상위클래스가 하위클래 스가 구현한 함수를 호출(Inverted Control Structure)한다.
템플릿 메소드 패턴은 Strategy pattern과 달리 알고리즘 전체를 바꾸는 것이 아니라 알고리즘의 일부만 변경한다.
템플릿 메소드에서 객체를 생성해야 될 경우에 종종 팩토리 메소드를 호출한다. 
abstract class Template {

    // 템플릿 메소드 : 메서드 앞에 final 키워드를 붙이면 자식 클래스에서 오버라이딩이 불가능함.
	// 자식 클래스에서 상위 템플릿을 오버라이딩해서 자기마음대로 바꾸도록 하는 행위를 원천 봉쇄
    public final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
    }

    // 상속하여 사용할 것이기 때문에 protected 접근제어자 설정
    protected abstract void primitiveOperation1();
    protected abstract void primitiveOperation2();
}
class ConcreteClass1 extends Template {

    @Override
    protected void primitiveOperation1() {}

    @Override
    protected void primitiveOperation2() {}
}

class ConcreteClass2 extends Template {

    @Override
    protected void primitiveOperation1() {}

    @Override
    protected void primitiveOperation2() {}
}
class Client {
   public static void main(String[] args) {
       // 1. 템플릿 메서드가 실행할 구현화한 하위 알고리즘 클래스 생성
       Template templateA = new ConcreteClass1();

       // 2. 템플릿 실행
       templateA.templateMethod();
   }
}

패턴 사용 시기

  • 클라이언트가 알고리즘의 특정 단계만 확장하고, 전체 알고리즘이나 해당 구조는 확장하지 않도록 할 때
  • 동일한 기능은 상위 클래스에서 정의하면서 확장, 변화가 필요한 부분만 하위 클래스에 구현할 때

패턴 장점

  • 클라이언트가 대규모 알고리즘의 특정 부분만 재정의하도록 해서 알고리즘의 다른 부분에 발생하는 변경 사항의 영향을 덜 받도록 한다.
  • 상위 클래스로 로직을 공통화해 코드의 중복을 줄일 수 있다.
  • 서브 클래스의 역할을 줄이고, 핵심 로직을 상위 클래스에서 관리하므로 관리가 용이해진다.
    • 헐리우드 원칙: 고수준 구성요소에서 저수준을 다루는 원칙

패턴 단점

  • 알고리즘의 제공된 골격에 의해 유연성이 오히려 제한될 수도 있다.
  • 알고리즘 구조가 복잡할수록 템플릿 로직 형태를 유지하기 어려워진다.
  • 추상 메소드가 많아지면서 클래스의 생성, 관리가 어려워질 수 있다.
  • 상위 클래스에서 선언된 추상 메소드를 하위 클래스에서 구현할 때, 그 메소드가 어느 타이밍에서 호출되는지 클래스 로직을 이해해야 할 필요가 있다.
  • 로직에 변화가 생겨 상위 클래스를 수정할 때, 모든 서브 클래스의 수정이 필요 할수도 있다.
  • 하위 클래스를 통해 기본 단계 구현을 억제하여 리스코프 치환 법칙Visit Website을 위반할 여지가 있다.