Template Method[Design Pattern]

SnowCat·2023년 4월 4일
1

Design Pattern

목록 보기
22/23
post-thumbnail

의도

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

문제

  • 데이터 마이닝 앱을 개발하고 있다 가정해보자.
  • 처음에는 Doc 파일만을 지원하다, 나중에는 pdf, csv 등의 다양한 파일 형식을 지원하게 되었다.
  • 이들의 알고리즘을 각각의 메서드로 정의했지만, 코드를 리팩토링하기 위해 확인해 보니 대부분의 과정이 비슷하고 일부분의 내용만 달라지게 되었다. 또한 이들을 처리하기 위해 클라이언트에 조건문이 있는데, 이 조건문은 시간이 지날수록 더욱 복잡하게 바뀌게 될 것이다.

해결책

  • 템플릿 메서드 패턴을 사용해 알고리즘을 여러 단계로 나누고 메서드로 변환한 뒤, 단일 템플릿 메서드 내부에 여러 메서드들의 호출을 넣기
  • 알고리즘을 사용하기 위해 클라이언트는 자신의 자식 클래스를 제공해야 하고, 모든 추상 단계를 구현하며, 필요하다면 여러 단계중 일부를 오버라이딩 해야 함

구조

/**
 * 추상클래스에서 알고리즘의 단계가 되는 여러 메서드들을 선언하며, 이들을 순차적으로 호출하는 템플릿 메서드도 선언을 하게 됨
 */
abstract class AbstractClass {
    /**
     * 템플릿 메서드에서 알고리즘의 호출 순서를 결정하게 됨
     */
    public templateMethod(): void {
        this.baseOperation1();
        this.requiredOperations1();
        this.baseOperation2();
        this.hook1();
        this.requiredOperation2();
        this.baseOperation3();
        this.hook2();
    }

    /**
     * 일부 메서드들은 추상 클래스 단계에서 구현을 할 수 있음
     */
    protected baseOperation1(): void {
        console.log('AbstractClass says: I am doing the bulk of the work');
    }

    protected baseOperation2(): void {
        console.log('AbstractClass says: But I let subclasses override some operations');
    }

    protected baseOperation3(): void {
        console.log('AbstractClass says: But I am doing the bulk of the work anyway');
    }

    /**
     * 서브클래스에서 구현해야하는 메서드들
     */
    protected abstract requiredOperations1(): void;

    protected abstract requiredOperation2(): void;

    /**
     * 빈 상태로 정의되어 있으며 상속을 받는 클래스들이 선택적으로 구현가능한 메서드들을 hook이라 부름
     */
    protected hook1(): void { }

    protected hook2(): void { }
}

/**
 * 구상 클래스에서 추상 클래스의 인터페이스를 구현
 */
class ConcreteClass1 extends AbstractClass {
    protected requiredOperations1(): void {
        console.log('ConcreteClass1 says: Implemented Operation1');
    }

    protected requiredOperation2(): void {
        console.log('ConcreteClass1 says: Implemented Operation2');
    }
}

class ConcreteClass2 extends AbstractClass {
    protected requiredOperations1(): void {
        console.log('ConcreteClass2 says: Implemented Operation1');
    }

    protected requiredOperation2(): void {
        console.log('ConcreteClass2 says: Implemented Operation2');
    }

    protected hook1(): void {
        console.log('ConcreteClass2 says: Overridden Hook1');
    }
}

/**
 * 클라이언트 코드
 */
function clientCode(abstractClass: AbstractClass) {
    abstractClass.templateMethod();
}

console.log('Same client code can work with different subclasses:');
clientCode(new ConcreteClass1());
/*
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
*/
console.log('');

console.log('Same client code can work with different subclasses:');
/*
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
*/
clientCode(new ConcreteClass2());

적용

  • 전체 알고리즘이나 알고리즘 구조는 유지하면서 클라이언트가 알고리즘 일부만 확장하도록 하고 싶을 때 사용
    단방향 알고리즘을 여러 단계로 분리시켜 자식 클래스들이 확장시킬 수 있도록 함
  • 거의 비슷한 알고리즘을 포함하는 여러 클래스가 있을 경우에 사용
    유사한 구현을 부모 클래스로 끌어올려 코드 중복을 방지

구현 방법

  1. 대상 알고리즘을 여러 단계로 나눌수 있는지, 어떤 단계가 공통적이고 차이가 있는지 확인
  2. 추상 기초 클래스를 만들고 알고리즘의 단계를 나누어 템플릿 메서드 구현
  3. 필요한 경우 일부 단계에 디폴트를 구현하고 훅을 추가함
  4. 알고리즘의 각 변형에서 새로운 구상 자식 클래스를 생성
    각 클래스는 모든 추상 단계들을 반드시 구현하고, 일부 선택 단계는 오버라이딩 할 수도 있음

장단점

  • 중복 코드를 부모 클래스로 가져올 수 있음
  • 클라이언트들이 대규모 알고리즘의 특정 부분만 오버라이드 해서 알고리즘의 다른 부분에 발생하는 변경에 영향을 덜 받게 할 수 있음
  • 일부 클라이언트들이 알고리즘의 제공된 골격에 의해 제한받을 수 있음
  • 자식 클래스를 통해 디폴트 단계 구현이 달라져 리스코프 치환 원칙을 위배할 수 있음
  • 단계가 많아질수록 유지가 어려워짐

출처:
https://refactoring.guru/ko/design-patterns/template-method

profile
냐아아아아아아아아앙

0개의 댓글