jsp

[디자인 패턴] 템플릿 메서드 패턴

사이버나그네 2024. 6. 19. 16:22

[배경]

이번 글에서는 디자인 패턴의 종류 중 하나인 템플릿 메서드에 대해 알아보자. 템플릿 메서드이 무엇인지, 패턴 구현 시 주의할 점은 무엇인지에 대해 알아보는 것만으로도 많은 도움이 될 것이라 생각한다.

 


 

[내용]

1. 템플릿 메서드 정의

템플릿 메서드 패턴은  부모 클래스에서 알고리즘의 골격을 정의하지만, 해당 알고리즘의 구조를 변경하지 않고 자식 클래스들이 알고리즘의 특정 단계들을 오버라이드​(재정의)​할 수 있도록 하는 행동 디자인 패턴이다.

 

2. 템플릿 메서드 패턴의 장단점

 - 템플릿 메서드 패턴의 장점

1. 코드 재사용성 증가로 인한 효육적 코드작성이 가능합니다. 상위 클래스에서 알고리즘의 공통 부분을 정의하고, 하위 클래스에서 세부 사항을 구현함으로써 코드의 재사용성을 높일 수 있다. 이를 통해 중복 코드를 줄이고, 유지보수가 용이해진다.

2. 알고리즘의 구조 변경이 용이하다. 알고리즘의 뼈대를 상위 클래스에서 정의하기 때문에, 알고리즘의 구조를 변경할 때 하위 클래스에 영향을 주지 않고 쉽게 수정할 수 있다. 하위 클래스는 상위 클래스에서 제공하는 템플릿에 맞춰 세부 구현만을 신경 쓰면 된다.

 

3. 확장 용이성이 증가한다. 새로운 하위 클래스를 추가하여 알고리즘의 새로운 변형을 쉽게 구현할 수 있다. 상위 클래스에서 제공하는 템플릿 메서드를 재사용하고, 필요한 부분만 재정의하면 된다.

 

 

 - 템플릿 메서드 패턴의 단점

1. 코드 복잡성이 증가된다. 상위 클래스와 하위 클래스 간의 계층 구조가 복잡해질 수 있습니다. 특히, 많은 하위 클래스가 존재할 경우, 코드의 가독성과 유지보수가 어려워질 수 있습니다.

2. 하위클래스에 대한 의존성의 증가에 따른 문제점이 발생 될 수 있다. 상위 클래스에서 정의한 템플릿 메서드가 하위 클래스에서 제대로 구현되지 않으면, 전체 알고리즘의 동작에 문제가 발생할 수 있습니다. 따라서 하위 클래스에서 모든 추상 메서드를 올바르게 구현해야 합니다.

 

3. 알고리즘의 제공된 골격에 의해 유연성이 제한될 수 있다. 상위 클래스에서 알고리즘의 뼈대를 고정하기 때문에, 알고리즘의 구조를 유연하게 변경하기 어려울 수 있습니다. 구조의 큰 변화를 원할 경우 템플릿 메서드 패턴이 적합하지 않을 수 있습니다.

3. 예시 

 - 템플릿 메서드 코드 예시

 

abstract class FileProcessor {
    private String path; // 생성자로 부터 파일경로를 받아와 저장

    public FileProcessor(String path) {
        this.path = path;
    }

    // 템플릿 메소드 (오버라이딩 못하게 final 처리)
    public final int process() {
        try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
            int result = getResult();
            String line = null;

            while ((line = reader.readLine()) != null) {
                result = caculate(result, Integer.parseInt(line));
            }
            return result;

        } catch (IOException e) {
            throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e);
        }
    }

    protected abstract int caculate(int result, int number);
    protected abstract int getResult();
}

 

class PlusFileProcessor extends FileProcessor{

    public PlusFileProcessor(String path) {
        super(path);
    }

    @Override
    protected int caculate(int result, int number) {
        return result += number;
    }
    
    @Override
    protected int getResult() {
        return 0;
    }
}

// 곱셈 연산 수행
class MultiplyFileProcessor extends FileProcessor{

    public MultiplyFileProcessor(String path) {
        super(path);
    }

    @Override
    protected int caculate(int result, int number) {
        return result *= number;
    }
    
    @Override
    protected int getResult() {
        return 1; // 곱셈은 초깃값이 0이면 결과도 멱등하니까
    }
}



class Client {
    public static void main(String[] args) {
        PlusFileProcessor plusFileProcessor = new PlusFileProcessor("numbers.txt");
        int result1 = plusFileProcessor.process();
        System.out.println(result1); // 15

        MultiplyFileProcessor multiplyFileProcessor = new MultiplyFileProcessor("numbers.txt");
        int result2 = multiplyFileProcessor.process();
        System.out.println(result2); // 120
    }
}

 

 - 템플릿 메서드 실제 사용 예시

 템플릿 메서드 접근 방식은 대량 주택 건설에 사용할 수 있다. 표준 주택 건설을 위한 건축 계획에서 토지 면적에 따른 주택공사의 일부 세부 사항들을 조정할 수 있도록 하는 탬플릿 메서드를 만들었다. 완성된 집이 다른 집들과 조금씩 다르도록 각 건축 단계​(예: 기초 쌓기, 골조공사, 벽 쌓기, 수도 및 전기 배선 설치 등)​는 약간씩 변경될 수 있다. 하지만 커다란 전체적인 골격관 순서는 비슷하게 (예: 기초 공사, 콘크리트 철근, 벽 마무리 , 도배 등등) 은 동일하므로 중복을 최대한 줄이게 설계를 할 수 있다.


[결론]

 템플릿 메서드이 무엇이고, 어떤 이점과 문제점이 있는지 살펴보았다. 정리하자면, 상속을 통해 중복되는 코드를 상위 클래스로 통일시켜 코드 중복을 제거하고, 메서드 시그니처가 같지만 내부 로직이 자식 클래스마다 다른 부분은 추상 메소드를 통해 상위 클래스에서 다형성으로 메서드를 실행할 수 있도록, 고수준의 타입으로 유지하라는 것이다. 어떻게 보면 상속의 기능을 극대화하는 패턴이라고 볼 수 있다. 한번 정해진 골격을 얼마나 잘 구성했느냐에 따라 이후의 복잡성과 유연성에 많은 영향을 끼치기에 초기에 데이터 분석을 통한 구성을 잘 하는것이 중요하다. 


[출처 및 참조]