본문 바로가기
디자인 패턴

템플릿 메서드 패턴

by oncerun 2022. 1. 15.
반응형

GOF 디자인 패턴에서 템플릿 메서드 패턴은 다음의 목적을 가지고 있다고 정의한다.

 

"작업에서 알고리즘의 골격을 정의하고 일부 단계를 하위 클래스로 연기합니다. 템플릿 메서드를 사용하면 하위 클래스가 알고리즘의 구조를 변경하지 않고도 알고리즘의 특정 단계를 재정의할 수 있습니다." [GOF]

 

부모 클래스에 변하지 않는 하나의 큰 템플릿을 지정하고 일부 변경되는 코드 조각을 자식 클래스에서 정의하여 자식 클래스의 오버 라이딩된 메서드를 통해 큰 템플릿의 전체 구조를 변경하지 않고도 특정 부분만을 변경하여 실행할 수 있다.

 

이는 자바의 상속과 오버라이딩을 통해서 다형성으로 문제를 해결하는 방법이다.

 

대걔 핵심인 비즈니스 로직을 처리하다 보면 해당 비즈니스 로직을 도와주는 부가적인 기능이 같이 개발되는 경우가 많다. 이러한 경우 부가적인 기능과 핵심 기능이 코드 상에서 동일 선상에 존재하는 것은 부가적인 기능의 변경이 비즈니스 로직에 영향을 미칠 수 있음을 뜻하기 때문에 좋은 코드 설계라고 할 수 없다.

 

1.  부모 클래스 준비(템플릿)

@Slf4j
public abstract class AbstractTemplate {

    public void execute(){
        log.info("변하지 않는 부분");
        call();  // 변하는 부분
        log.info("변하지 않는 부분");
    }

    protected abstract void call();

}

 

이 추상 클래스인 AbstractTemplate은 추상 메서드로 call()을 지정하고 자식 클래스가 해당 클래스를 상속받아 call()을 오버 라이딩을 하여 실행되는 것이다.

 

2. 테스트 준비

  • AbstractTemplate을 상속받은 구현체 or 혹은 익명 내부 클래스로 정의
  • call을 오버라이드하여 클라이언트의 핵심 비즈니스 로직을 정의

 

생각해보니 핵심 비지니스의 Return타입을 고려하지 않았다. 제네릭으로 다시 AbstractTemplate을 만들어보자.

@Slf4j
public abstract class AbstractTemplate<T> {

    public T execute(){
        log.info("변하지 않는 부분");
        T result = call();// 변하는 부분
        log.info("변하지 않는 부분");

        return result;
    }

    protected abstract T call();

}

 

이제 클라이언트에서 사용하는 부분과 그에 따른 결과를 맞고 검증하는 테스트 코드를 작성할 것이다.

@Test
void templateMethodPatternExample() {

    //클라이언트 사용
    AbstractTemplate<String> template = new AbstractTemplate<>() {
        @Override
        protected String call() {
            log.info("String을 반환하는 핵심 비지니스 로직");
            return "String";
        }
    };
    //template의 전체 코드조각 실행
    String result = template.execute();
    //결과
    Assertions.assertThat(result).isEqualTo("String");
}

* void를 반환하는 경우 계속 에러가 발생했는데 Void로 반환 타입을 설정하고 return null;을 하면 된다. 

 

 

여기서 짚고 넘어가야할 부분은 변하는 것과 변하지 않는 것을 분리했다는 점. 핵심은 변하고 부가는 변하지 않는다. 이 둘을 모듈화 했다. 이로써 얻어지는 이점은 다음과 같다. 

 

1. 핵심로직의 변경이 큰 템플릿에 영향을 주지 않는다.

2. 부가로직의 변경이 핵심 로직에 영향을 주지 않는다.

 

 

하지만 모든 패턴에는 장단점이 있듯이 해당 패턴에도 문제가 발생한다.

 

자식 클래스에서 부모 클래스의 기능을 사용하지 않기 때문에 상속을 사용하는 방법이 맞는 것인가 의문이 든다. 또한 자식 클래스는 부모 클래스를 의존하고 있기 때문에 부모 클래스의 변경에 영향을 받을 수밖에 없다. 

또 템플릿 메서드 패턴은 상속 구조이기 때문에 별도의 클래스를 만들어 사용하거나, 익명 내부 클래스를 사용한다는 점이 코드를 매우 지저분하게 만든다.

 

이러한 부분을 개선하기위해 나온 디자인 패턴이 바로 Strategy Pattern이다. 

다음에는 Strategy Pattern의 의도와 사용방법, 개선사항을 공부한다.

 

 

반응형

'디자인 패턴' 카테고리의 다른 글

데코레이터 패턴 + [F]  (0) 2022.02.19
빌더 패턴 + [F]  (0) 2022.02.19
데코레이터 패턴  (0) 2022.01.21
프록시 패턴  (0) 2022.01.20
전략 패턴  (0) 2022.01.17

댓글