디자인 패턴 - Template Method Pattern

bp.chys·2020년 5월 20일
0

OOP & Design Pattern

목록 보기
13/17

템플릿 메서드 패턴

  • 템플릿 메서드 패턴은 실행 과정이 동일한 절차를 가진 코드를 작성할 때 일부 과정의 구현만 다형성으로 다르게 대입하는 디자인 패턴이다.
  • 실행 과정을 구현한 상위 클래스실행 과정의 일부 단계를 구현한 하위 클래스로 구성된다.
  • 상위 클래스는 실행 과정을 구현한 템플릿 메서드를 제공한다.
    • 이 때, 일부 단계는 추상 메서드를 호출하는 방식으로 구현된다.
  • 일반적으로는 하위 클래스가 흐름을 제어하지만, 템플릿 메서드 패턴에서는 상위 클래스에서 흐름을 제어한다는 것이 특징이다.

예시

  • 청소기 프로그램을 만들어보자.
  • 먼저 claen의 책임을 갖고 있는 청소 인터페이스를 만들자.
public interface Cleaning {
    void clean(boolean isRoomDirty);
}
public abstract class Cleaner implements Cleaning {
    //템플릿 메서드 (= hook)
    @Override
    public void clean(boolean isRoomDirty) {
        turnOn();
        information(); // 추상 메서드 -> 다형성
        if (isRoomDirty) {
            System.out.println("청소를 시작합니다.");
        }
        turnOff();
    }

    private void turnOn() {
        System.out.println("전원이 켜집니다.");
    }

    private void turnOff() {
        System.out.println("전원이 꺼집니다.");
    }
    
    protected abstract void information();
}
  • Cleaner 추상 클래스를 상속하여 information() 메서드를 구현하여 템플릿 메서드를 완성시켜보자.
  • 아래와 같이 구현체마다 information() 메서드를 재정의해서 구현체마다 다른 훅의 결과를 볼 수 있다.
public class RobotCleaner extends Cleaner {
    private String name;
    private int power;
    private int battery;

    public RobotCleaner(final String name, final int power, final int battery) {
        this.name = name;
        this.power = power;
        this.battery = battery;
    }

    @Override
    protected void information() {
        System.out.println("I am Robot Cleaner");
        System.out.println(String.format("이름 : %s, 파워 : %d, 
        	배터리 : %d%%", name, power, battery));
    }
}

템플릿 메서드 패턴 + 전략 패턴

  • 기존의 템플릿 메서드 패턴은 추상클래스를 상속하여 상위 클래스에서 흐름을 제어한다는 특징이 있다. 이는 기능이 확장될 때마다 불필요한 조합이 늘어날 수 있다는 단점이 있다.
  • 하지만 만약 전략 패턴과 함께 사용한다면 상속보다는 합성(Composition) 방식으로 좀 더 유연한 설계를 가져갈 수 있다.
  • 위 예시에서 Cleaner가 RobotCleaner를 인스턴스 변수로 갖도록 변경하면된다.
public class Cleaner implements Cleaning {
    private RobotCleaner cleaner;
    
    public Cleaner(RobotCleaner cleaner) {
        this.cleaner = cleaner;
    }
    
    //템플릿 메서드 (= hook)
    @Override
    public void clean(boolean isRoomDirty) {
        turnOn();
        cleaner.information();
        if (isRoomDirty) {
            System.out.println("청소를 시작합니다.");
        }
        turnOff();
    }

    private void turnOn() {
        System.out.println("전원이 켜집니다.");
    }

    private void turnOff() {
        System.out.println("전원이 꺼집니다.");
    }
}

SOLID 관점에서 본 템플릿 메서드 패턴

  • 훅 메서드가 정의된 상위 클래스와 부분 로직에 대해 재정의하는 구현 클래스가 분리 되어있으므로 단일 책임 원칙(SRP)을 따르고 있다.
  • 구현 클래스가 얼마든지 추가되더라도, 추상클래스는 변경되지 않으므로 개방 폐쇄 원칙(OCP) 역시 잘 지켜지고 있다.
  • 추상 메서드를 재정의하는 하위 클래스의 메서드가 도메인 규칙에 맞게 잘 재정의하고 있으므로 리스코프 치환 원칙(LSP)도 잘 따르고 있다.
  • 추상 메서드를 사용하는 쪽에서 용도에 맞게 정의하고 있고, 이를 구현하는 클래스 역시 한 곳에서 사용되고 있으므로 인터페이스 분리 원칙(ISP)도 잘 지켜지고 있다.
  • 추상 클래스를 통해 결합도를 낮추고 있으므로 의존성 역전 원칙(DIP)도 따르게 된다.

결론

템플릿 메서드 패턴은 동일한 절차가 반복되는 구조를 가지고 있고, 일부 과정만 다른 로직으로 대체하고 싶을 때 사용할 수 있는 패턴이다. 흐름을 가지고 있는 뼈대(훅)메서드는 상위 클래스에 정의가 되고, 상위 클래스에서 하위 클래스의 메서드를 호출한다는게 특징이다.

전략 패턴과 함께 사용한다면 합성(Composition)의 장점도 함께 누릴 수 있다. 다만 구현이 좀 더 복잡해지는 단점이 있을 것이다. 템플릿 메서드 패턴 역시 쉬우면서도 개발할 때 종종 사용되는 패턴이니 잘 알아두면 유용한 패턴이라고 생각한다.


참고자료

  • 개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴 - 최범균
profile
하루에 한걸음씩, 꾸준히

0개의 댓글