_ 개발

[DESIGN PATTERN/JAVA] Template Method - 템플릿 메서드 패턴

옴뇽뇽 2024. 11. 13. 16:19

목 차

Template Method : 하위 클래스에서 구체적으로 처리하기

Template Method 패턴의 구성 요소

Template Method 패턴의 구현 예시

Template Method 패턴의 특징

 

Template Method : 하위 클래스에서 구체적으로 처리하기

상위 클래스에서는 처리를 위한 기본 골격를 정하고, 하위 클래스에서 그에 대한 구체적 내용을 결정하도록 하는 디자인 패턴이다. 일반적인 알고리즘의 구조를 상위 클래스에 작성하고, 이에 대한 세부적인 동작을 하위 클래스에서 구현하는 방식으로 코드를 구성한다.
이 패턴의 역할은  '템플릿'이라는 이름에서도 그 쓰임이 쉽게 예측이 가능하다. 일반적으로 우리가 아는 문서 작성 템플릿, 웹페이지 디자인 템플릿 등을 떠올리면 된다. 어떤 작업을 하는데 있어 정해진 기본틀이나 순서의 흐름이 있고, 우리는 그 틀/흐름을 기본으로 유지하되, 각 단계 세부 내용은 필요에 따라 다르게 채울 수 있다.

디자인 패턴 Template method 패턴을 설명하는 이미지


Template Method 패턴의 구성 요소 

Template Method 패턴 다이어그램

1. AbstractClass

  • TemplateMethod가 구현되어 있고, 그 안에 사용되는 추상 메서드들(method1~3)을 선언
  • 추상 메서드는 어떤 기능을 하는지만 정해놓고, 실제 어떻게 작동되는지는 ConcreteClass가 구현

2. ConcreteClass

  • AbstractClass를 상속받아 그 안에 선언된 추상 메서드를 구체적으로 구현
  • 직접 인스턴스 생성(new)하지 않고 인스턴스 생성을 위한 메서드를 호출 함으로서 구체적 클래스 종속 탈피

Template Method 패턴의 구현 예시

이 패턴을 사용한 예제로 문자 또는 문자열을 5회 반복해서 출력하는 프로그램을 만들어 보자.

Template Method 패턴 예제 프로그램 다이어그램
Template Method 패턴 예제 프로그램 다이어그램

 
 
(1) AbstractDisplay 클래스

public abstract class AbstractDisplay {
    // open, print, close는 하위 클래스에 구현을 맡기는 추상 메소드 
    public abstract void open();
    public abstract void print();
    public abstract void close();

    // display는 AbstractDisplay에서 구현됨
    public final void display() {
        open();
        for (int i = 0; i < 5; i++) {
            print();
        }
        close();
    }
}
  • 문자/문자열을 입력하다 5회 표시하기 위한 인터페이스를 결정하는 추상 클래스이다.
  • display 메서드 : open, print, close 메서드를 사용하여 문자/문자열을 5회 표시한다.
  • open, print, close 메서드는 추상 메서드로 하위 클래스에서 각각 적절하게 구현한다.

(2) CharDisplay 클래스

public class CharDisplay extends AbstractDisplay {
    private char ch;

    // 생성자 
    public CharDisplay(char ch) {
        this.ch = ch;
    }

    @Override
    public void open() {
        System.out.print("<<");
    }

    @Override
    public void print() {
        System.out.print(ch);
    }

    @Override
    public void close() {
        System.out.println(">>");
    }
}
  • 문자 출력에 적절하도록 AbstractDisplay에서 상속 받은 추상 메서드를 구현한다.
  • ch 필드 : 생성자에서 문자(char) 타입 인수를 전달받아 이를 저장한다.
  • open 메서드 : 개시 문자열 출력한다. → “<<”
  • print 메서드 : ch 필드에 저장된 문자를 출력한다.
  • close 메서드 : 종료 문자열 출력한다. → “>>”

(3) StringDisplay 클래스

public class StringDisplay extends AbstractDisplay {
    private String string; 
    private int width;

    // 생성자 
    public StringDisplay(String string) {
        this.string = string;
        this.width = string.length();
    }

    @Override
    public void open() {
        printLine();
    }

    @Override
    public void print() {
        System.out.println("|" + string + "|");
    }

    @Override
    public void close() {
        printLine();
    }

    private void printLine() {
        System.out.print("+");
        for (int i = 0; i < width; i++) {
            System.out.print("-");
        }
        System.out.println("+");
    }
}
  • 문자열 출력에 적절하도록 AbstractDisplay에서 상속 받은 추상 메서드를 구현한다.
  • string 필드 : 생성자에서 문자열(String) 타입 인수를 전달받아 이를 저장한다.
  • width 필드 : 문자열 길이를 바이트 단위로 계산하여 저장한다. (int 타입)
  • open, close 메서드 : printLine 메서드를 호출한다.
  • print 메서드 : string 필드에 저장된 문자열을 가지고 "|문자열|"과 같이 출력한다.
  • printLine 메서드 : open과 close에서 호출되어 "+----+" 모양의 문자열을 표시한다. 문자열의 길이에 따라 함께 조정된다.

클라이언트 실행

CharDisplay와 StringDisplay 인스턴스를 각각 만들어 display 메서드를 호출했을 때 결과물은 상이하다.

public class Main {
    public static void main(String[] args) {
        AbstractDisplay d1 = new CharDisplay('S'); // 'S'를 가진 CharDisplay 인스턴스 d1 생성
        AbstractDisplay d2 = new StringDisplay("Log for ()."); // "Log for ()."를 가진 StringDisplay 인스턴스 d2생성
        AbstractDisplay d3 = new StringDisplay("Hello!"); // "Hello!"를 가진 StringDisplay 인스턴스 d3 생성

        d1.display();
        d2.display();
        d3.display();
    }
}
  • d1, d2, d3 모두 같은 AbstractDisplay의 하위 클래스의 인스턴스이므로 상속한 display 메서드를 호출할 수 있으며, 실제 동작은 CharDisplay나 StringDisplay 클래스에서 구현된대로 정해진다.
  • 출력 결과는 아래와 같다.
<<SSSSS>>
+-----------+
|Log for ().|
|Log for ().|
|Log for ().|
|Log for ().|
|Log for ().|
+-----------+
+------+
|Hello!|
|Hello!|
|Hello!|
|Hello!|
|Hello!|
+------+

Template Method 패턴의 특징

알고리즘의 기본 뼈대 정의

  • 전체 구조를 상위 클래스의 템플릿 메서드에 정의한다.
  • 템플릿 메서드는 고정된 작업의 흐름을 갖고 있고, 일부 단가를 하위 클래스에서 재정의 될 수 있게 메서드로 추상화된다.

로직 공동화를 통해 유지보수성&재사용성 증가

  • 공통적으로 반복되는 코드를 포함하는 클래스(메서드)를 만들 때, 공통 로직을 템플릿 메서드로 구현하게 되면 해당 부분만 수정하면 되기 때문에 유지보수가 수월해진다.
  • 기본 뼈대를 이루는 공통 구조는 상위 클래스에서 작성하기 때문에 중복된 코드 작성을 줄일 수 있다.

상속을 통한 확장

  • 하위 클래스에서 상위 클래스의 템플릿 메서드를 확장해 구체적인 구현을 할 수 있기 때문에 코드의 확장성이 높아진다.

상위 클래스와 하위 클래스의 동일시 : 리스코프 치환 원칙(LSP)

  • 상위 클래스 타입 변수에 어떠한 하위 클래스 인스턴스를 대입해도 문제가 없도록 만들어야한다.

Ref.