1. 템플릿 메소드란?


  • 템플릿(template)의 정의
    • 일정한 틀, 형식
    • 파워포인트 템플릿을 생각하면 된다.
      • 전체적인 틀, 디자인을 잡아놓았지만 채워넣을 내용, 글꼴, 사진등은 작성자가 채워넣는다.

  • 템플릿 메소드
    • 알고리즘의 구조, 뼈대를 정의하는 메소드
    • 템플릿 메소드에서 호출하는 각각의 메소드들은 하위 클래스에서 재정의해서 사용한다.

public abstract class AbstractClass {

    //알고리즘의 구조를 템플릿 메소드로 정의한다.
    final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteMethod1();
    }

    //실제 알고리즘은 하위 클래스에서 재정의하여 사용하는 추상 메소드
    abstract void primitiveOperation1();
    abstract void primitiveOperation2();

    void concreteMethod1() {
        //구현
    }
}

  • 템플릿 메소드 패턴
    • 템플릿 메소드를 사용하여 알고리즘의 골격을 정의한다.
    • 여러 단계 중 변하지 않는 공통적인 부분은 직접 구현한다.
    • 하위 클래스별로 다른 부분은 하위 클래스에서 직접 구현해서 사용한다.
    • 알고리즘이 변하는것을 방지하기 위해 템플릿 메소드는 final로 선언한다.

class_diagram


2. 예시


  • 웨이트 트레이닝 운동 플래너
    • 수준별로 초급자, 고급자로 나눈다.

public abstract class TrainingPlan {

    //알고리즘의 구조를 정의한 템플릿 메소드
    final void doExercise() {
        squate();
        getRest();

        deadlift();
        getRest();

        benchpress();
        getRest();
    }

    abstract void squate(); //스쿼트
    abstract void deadlift(); //데드리프트
    abstract void benchpress(); //벤치프레스

    //휴식은 공통적으로 1분간 쉬므로 직접 구현
    void getRest() {
        System.out.println("1분간 휴식");
    }
}

초급자 플랜

public class BeginnerPlan extends TrainingPlan {
    @Override
    void squate() {
        System.out.println("30kg으로 스쿼트를 합니다.");
    }

    @Override
    void deadlift() {
        System.out.println("30kg으로 데드리프트를 합니다.");
    }

    @Override
    void benchpress() {
        System.out.println("30kg으로 벤치프레스를 합니다.");
    }
}

고급자 플랜

public class AdvancedPlan extends TrainingPlan {
    @Override
    void squate() {
        System.out.println("60kg으로 스쿼트를 합니다.");
    }

    @Override
    void deadlift() {
        System.out.println("60kg으로 데드리프트를 합니다.");
    }

    @Override
    void benchpress() {
        System.out.println("60kg으로 벤치프레스를 합니다.");
    }
}

3. hook 메소드


public abstract class AbstractClass {

    final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteMethod1();
        hook2(); //후크
    }

    abstract void primitiveOperation1();
    abstract void primitiveOperation2();

    void concreteMethod1() {
        //구현
    }

    void hook(){}
}
  • hook 메소드
    • 아무것도 하지 않거나 기본적인 내용만 구현되어 있는 메소드
    • 서브클래스에서 오버라이딩 해도 되고 안해도 된다.
    • 서브 클래스에서 재정의하면 알고리즘에 끼어들 수 있다.

  • 운동 플래너에서 후크의 활용 예시
    • 운동이 힘들수록 쿨다운은 안전을 위해 중요해진다.
    • 초급자 플랜은 쿨다운 운동을 하지 않아도 되기때문에 그대로 둔다.
    • 고급자 플랜은 쿨다운 운동을 해야 하므로 재정의해서 사용한다.
public abstract class TrainingPlan {

    //알고리즘의 구조를 정의한 템플릿 메소드
    final void doExercise() {
        squate();
        getRest();

        deadlift();
        getRest();

        benchpress();
        getRest();

        coolDown();
    }

    abstract void squate(); //스쿼트
    abstract void deadlift(); //데드리프트
    abstract void benchpress(); //벤치프레스

    //휴식은 공통적으로 1분간 쉬므로 직접 구현
    void getRest() {
        System.out.println("1분간 휴식");
    }

    //후크
    void coolDown(){}
}

  • 후크를 쓰는 대신 추상 메소드를 만들어두고 쓰면 되지 않은가?
    • 알고리즘의 특정 단계를 꼭 제공해야 하는 경우 추상 클래스를 사용한다.
    • 알고리즘이 선택적으로 동작해도 되는 경우 후크를 쓴다.

4. 장점


  • 공통, 중복 코드를 재사용

  • 여러 곳에서 동작이 조금씩 다른 형태로 필요할 경우에 유용하다.

  • 알고리즘의 실행 절차가 바뀌면 템플릿 메소드만 변경하면 된다.

  • 새로운 하위 클래스를 쉽게 추가할 수 있는 프레임워크를 재공해준다.

    • 하위 클래스에 의존하는 부분만 코딩하면 된다.
  • 알고리즘에 대한 지식이 템플릿 메소드에 집중되어있어 파악하기가 편리하다.


5. 정리


템플릿 메소드를 사용함으로써 전체적인 로직의 뼈대를 정해놓는다. 세부적인 알고리즘들 중 공통적인 부분은 추상 클래스에서 직접 구상 메소드를 정의하고 하위 클래스마다 달라져야 하는 부분은 확장할 때 구현해서 사용한다. 팩토리 메소드 패턴과 헷갈릴 수 있다. 팩토리 메소드 패턴에서는 객체 생성을 서브클래스에 위임하는 것이 목적이었다. 그러나 템플릿 메소드 패턴에서는 알고리즘 뼈대를 final로 선언한 템플릿 메소드로 일관적이게 고정시키되, 세세한 알고리즘의 구현은 서브클래스로 위임하는 게 목표다. 이렇게 하면 클라이언트는 구현이 아닌 추상 클래스에 의존하게 되고 중요한 디자인 원칙인 의존성 역전 원칙(DIP)를 지킬 수 있다.

'소프트웨어 공학 > 디자인패턴' 카테고리의 다른 글

컴포지트(Composite) 패턴  (0) 2020.06.28
이터레이터(Iterator) 패턴  (0) 2020.06.28
퍼사드(Facade) 패턴  (0) 2020.06.28
어댑터(Adapter) 패턴  (0) 2020.06.24
커맨드(Command) 패턴  (0) 2020.06.20

+ Recent posts