디자인패턴(2) - 템플릿 메소드 패턴

백엔드류·2024년 5월 14일

Design Pattern

목록 보기
2/2

템플릿 메소드 패턴

GoF의 디자인 패턴에 의하면, 템플릿 메소드 패턴이란 알고리즘의 구조를 메소드에 정의하고, 하위 클래스에서 알고리즘 구조의 변경없이 알고리즘을 재정의 하는 패턴이다. 알고리즘이 단계별로 나누어 지거나, 같은 역할을 하는 메소드 이지만 여러곳에서 다른 형태로 사용이 필요한 경우 유용한 패턴이다.

토비의 스프링에 의하면, 템플릿 메소드 패턴이란 상속을 통해 슈퍼클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법. 변하지 않는 기능은 슈퍼클래스에 만들어 두고 자주 변경되며 확장할 기능은 서브클래스에서 만들도록 한다.


⭐ 둘 다 하위 클래스에서 사용되지만, 변하지 않는 기능을 상위 클래스에 저장해 놓고, 확장할 기능은 서브클래스에서 만들도록 설계한다는 내용을 담고 있다.



템플릿 메소드 패턴의 예제

만약 두 개의 라면을 끓이는 과정이 아래와 같다고 가정하자.

<신라면>
1. 물을 끓인다.
2. 면을 넣는다.
3. 계란을 넣는다.
4. 4분 기다린다.

<너구리>
1. 물을 끓인다.
2. 면을 넣는다.
3. 콩나물을 넣는다.
4. 5분 기다린다.



Java 코드 구현

public class ShinRamen {                 // 신라면 조리 방법
    public void boilWater() {
        System.out.println("물을 끓인다.");
    }

    public void putNoodles() {
        System.out.println("면을 넣는다.");
    }

    public void putEgg() {
        System.out.println("계란을 넣는다.");
    }

    public void waitForMinutes() {
        System.out.println("4분 기다린다.");
    }
}
public class RaccoonRamen {              // 너구리 조리 방법
    public void boilWater() {
        System.out.println("물을 끓인다.");
    }

    public void putNoodles() {
        System.out.println("면을 넣는다.");
    }

    public void putBeanSprouts() {
        System.out.println("콩나물을 넣는다.");
    }

    public void waitForMinutes() {
        System.out.println("5분 기다린다.");
    }
}

위 두개의 코드에서, 물을 끓이는 것과 면을 넣는 행위는 완전히 동일한 코드이다. 따라서 Ramen이라는 클래스를 정의하여 중복된 코드를 제거할 수 있다. 그리고 추가로 '무언가'를 넣는 행위와 'x분' 기다린다는 행위가 유사하다. 템플릿 메소드 패턴은 이것도 추상화하는것이 목표이다.



public abstract class Ramen {            //추상클래스 선언

    public final void makeRamen() {            // 템플릿 메소드
        boilWater();
        putNoodles();
        putExtra();
        waitForMinutes();
    }

    private void boilWater() {
        System.out.println("물을 끓인다.");
    }

    private void putNoodles() {
        System.out.println("면을 넣는다.");
    }

    protected abstract void putExtra();       // 추상메소드

    protected abstract waitForMinutes()       // 추상메소드
    
    public void eat() {                       // 훅 메소드
    	System.out.println("냄비에 담습니다.");
    }
           
    }
  • 템플릿 메소드 : 알고리즘의 구조를 정의하고 구체적인 단계를 호출하며 각 단계의 실행 순서를 결정
    • 보통 final로 선언하여 하위 클래스에서 재정의할 수 없도록 한다. 이는 알고리즘의 구조를 변경하지 않고 구체적인 단계만 오버라이딩 할 수 있도록 한다.

  • 훅 메소드 : 템플릿 메소드에서 호출되는 메소드로, 기본 구현이 제공되어도 되고 필요에 따라 하위 클래스에서 재정의 될 수 있다.
    • 알고리즘의 일부가 아니며 선택적으로 사용한다. 하위 클래스에서 필요에 따라 오버라이딩 하여 기능을 확장하여 변경할 수 있다.

  • 추상 메소드 : 상위 클래스에서 선언만 되고 구현은 반드시 하위 클래스에서 구현되어야 한다.


코드 수정

public class ShinRamen extends Ramen {

    @Override
    public void putExtra() {
        System.out.println("계란을 넣는다.");
    }

    @Override
    public void waitForMinutes() {
        System.out.println("4분 기다린다.");
    }
}
public class RaccoonRamen extends Ramen {

    @Override
    public void putExtra() {
        System.out.println("콩나물을 넣는다.");
    }

    @Override
    public void waitForMinutes() {
        System.out.println("5분 기다린다.");
    }
}



정리

  • 재사용성이 크게 증가한다.
  • 공통된 코드들은 템플릿 메소드에 넣어둔다.
  • 반드시 구현해야 되는 추상메서드와 선택적 오버라이딩이 가능한 훅 메소드를 따로 둔다.
  • 템플릿 메소드가 추상메소드, 훅 메소드를 호출하는 구조로 되어있어 전체 알고리즘 구조를 보호하면서도 부분적인 수정이 가능해진다.


참고 : https://steady-coding.tistory.com/384

profile
공부한 내용을 정리한 블로그입니다 & 백엔드 개발자

0개의 댓글