• 추상 클래스로 템플릿을 제공하고 서브 클래스에서 구체적으로 구현하는 패턴
  • 즉, 특정 작업을 처리하는 부분을 서브 클래스로 캡슐화하여 수행하도록 설정
  • 전체적인 흐름은 동일하면서 부분적으로 코드가 다른 경우 사용하면 코드 중복을 최소화 할 수 있다

image

  • Abstract Class : 템플릿을 제공하는 추상클래스
  • Concrete Class : 특정 작업을 처리하는 서브클래스

구현

  • Abstract Class
    • Hook(후크) : 추상 클래스에 선언되지만 기본적인 내용만 구현되어 있거나 아무것도 들어 있지 않은 메서드
    • 후크를 하위 클래스에서 오버라이드 할 수도 있고 그냥 넘어갈 수도 있다
    • 상황에 따라 알고리즘의 진행을 변경할 수 있다
public abstract class Teacher {
    public final void work() {        // 템플릿 메서드
        inside();
        attendance();
        teach();
        if (!hasNextClass()) {
          outside();
        }
    }

    // 서브 클래스에서 확장이 필요한 부분
    public abstract void teach();
	
    // 공통 메서드
    private void inside() {
        System.out.println("선생님이 강의실로 들어옵니다.");
    }
    private void attendance() {
        System.out.println("선생님이 출석을 부릅니다.");
    }
    private void outside() {
        System.out.println("선생님이 강의실을 나갑니다.");
    }

    public boolean hasNextClass() {     // Hook
        return false;
    }
    
}
  • Concrete Class
class KoreanTeacher extends Teacher {
    @Override
    public void teach() {
        System.out.println("선생님이 국어를 수업합니다.");
    }
    @Override
    public boolean hasNextClass() {     
        return true;
    }
}
 
class MathTeacher extends Teacher {
    @Override
    public void teach() {
        System.out.println("선생님이 수학을 수업합니다.");
    }
    @Override
    public boolean hasNextClass() {     
        return true;
    }
}

class EnglishTeacher extends Teacher {
    @Override
    public void teach() {
        System.out.println("선생님이 영어를 수업합니다.");
    }
}
  • Main
public class Main {
    public static void main(String args[]){
        Teacher kr = new KoreanTeacher();
        Teacher mt = new MathTeacher();
        Teacher en = new EnglishTeacher();

        kr.work();
        mt.work();
        en.work();
    }
}

익명 내부클래스 사용

  • 클래스가 계속 늘어나는 것을 막기 위해 익명 내부클래스를 사용할 수도 있다
public class Main {
    public static void main(String args[]){
        Teacher teacher = new Teacher() {
            @Override
            public void teach() {
                System.out.println("선생님이 수업합니다.");
            }
        };
        teacher.work();
    }
}

장점

  1. 중복 코드를 줄일 수 있다
  2. 템플릿 코드를 변경하지 않고 상속받아 특정부분만 변경할 수 있다

단점

  1. LSP를 위배할 수도 있다
    • 자식클래스는 부모클래스의 기능을 전혀 사용하고 있지 않다
  2. 상속을 통해 부모클래스를 의존하고 있다
    • 부모클래스에 변경이 일어나면 자식클래스에도 영향을 미친다
  3. 알고리즘 구조가 복잡할 수록 템플릿을 유지하기 어려워진다
  • 템플릿 메소드보다 전략패턴을 선택하면 1, 2번을 해결할 수 있다

예시

  • 정렬이 필요한 곳에 Comparable를 implement하여 compareTo() 구현

템플릿 메서드 VS 전략

  • 템플릿 메서드
    • 알고리즘의 개요를 정의하고(템플릿) 일부 처리를 하위 클래스에게 넘겨 불완전한 알고리즘을 보충구현한다
  • 전략
    • 사용하는 클래스의 알고리즘을 완전히 구현한다