템플릿 메소드 패턴, 전략 패턴, 템플릿 콜백 패턴

조갱·2024년 3월 16일
0

스프링 강의

목록 보기
11/16

템플릿 메소드 패턴

정의

GOF 디자인 패턴의 행위 패턴으로 분류되는 템플릿 메소드는,
GOF 패턴에서 아래와 같이 정의하고있다.

이보다 더 깔끔?한 정의는 못본것 같아서, 아래 정의만 봐도 충분할 듯 하다.

메소드 내에 알고리즘의 뼈대를 정의하고, 일부 단계를 하위클래스로 연기한다.
템플릿 메소드는 하위클래스가 알고리즘의 구조를 변경하지 않고, 특정 스텝을 재정의하도록 한다.

Defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithms structure.

구조

템플릿 메소드 패턴의 클래스 다이어그램은 아래와 같다.

AbstractTemplate 클래스는 abstract class 로 정의하고, execute 메소드에 기본 골격이 되는 알고리즘이 들어간다.

이후, AbstractTemplate 클래스를 상속받아 call() 을 구현하고, execute() 메소드를 호출한다.

예제 코드

일상 생활에서, 밖에 나가는 상황으로 가정한다.
위에서 언급한 정의를 풀어보면

  • 메소드 내에 알고리즘의 뼈대를 정의하고,
    • OutTemplate의 out() 로직이다. 밖에 나가기 위해서는
      일어나고, 나가는 과정이 필수이다. 그 사이에 준비 과정은 목적에 따라 다르다.
  • 일부 단계를 하위클래스로 연기한다.
    • 나가는 목적이 회사인 경우, 대충 준비한다. (WorkOutTempalte)
    • 나가는 목적이 놀러가는 경우, 열심히 준비한다. (PlayOutTemplate)
  • 템플릿 메소드는 하위클래스가 알고리즘의 구조를 변경하지 않고, 특정 스텝을 재정의하도록 한다.
    • out() 이라는 알고리즘 구조 속에서, 나가는 목적(특정 스텝)에 따라 결과가 다름을 알 수 있다.
abstract class OutTemplate {
    fun out() {
        println("일어난다.")
        readyProcess()
        println("나간다.")
    }

    abstract fun readyProcess()
}

class WorkOutTemplate: OutTemplate() {
    override fun readyProcess() {
        println("대충 씻는다.")
        println("대충 옷을 입는다.")
    }
}

class PlayOutTemplate: OutTemplate() {
    override fun readyProcess() {
        println("노래를 부르며 씻는다.")
        println("화장도 한다.")
        println("퍼스널 컬러에 맞춰 옷을 꾸며입는다.")
    }
}
class TemplateMethodTest {
    @Test
    fun outTest(){
        WorkOutTemplate().out()
        PlayOutTemplate().out()
    }
}
일어난다.
대충 씻는다.
대충 옷을 입는다.
나간다.

일어난다.
노래를 부르며 씻는다.
화장도 한다.
퍼스널 컬러에 맞춰 옷을 꾸며입는다.
나간다.

장단점

장점

  • 알고리즘의 뼈대가 정의되어있기 때문에, 변경 사항에 영향이 적다.
  • 중복 코드를 줄일 수 있다.

단점

  • 알고리즘의 뼈대를 정의하기 때문에, 유연한 확장이 불가능하다. (확장이 제한적이다.)
  • 자식 클래스를 이상하게 코딩하면, 리스코프 치환 원칙을 위배할 수 있다.
  • 하위 스텝들이 많을수록, 유지보수가 어렵다.
  • 상속의 단점을 그대로 받는다. (자바는 다중상속이 불가능하다.)
  • 부모와 강결합된다. (결합도가 높을수록 안좋다.)
  • 자식 클래스는 단순히 step을 재정의 하기 위해 사용된다.
    따라서 부모의 기능은 사용하지 않는데, 부모를 알아야만 한다.

전략 패턴

위에 장단점을 보면, 장점보다 단점이 많음을 한눈에 알 수 있다.
이러한 이유 때문에, 템플릿 메소드 패턴과 비슷하지만 인터페이스를 사용하여 상속의 단점을 제거할 수 있는 전략 패턴을 사용하기도 한다.

템플릿 메소드 패턴과 비교

템플릿 메소드 패턴은, 부모 패턴에서 알고리즘의 뼈대를 구현하고
일부 변하는 step을 서브클래스에 구현하여 문제를 해결했다.

전략 패턴은 변하지 않는 부분(템플릿 역할)을 Context 라는 곳에 두고, 변하는 부분(서브클래스, step 구현 역할)을 Strategy 라는 인터페이스를 만들고 해당 인터페이스를 구현하도록 해서 문제를 해결한다.

즉, 템플릿 메소드는 상속을 통해 문제를 해결하는 반면
전략 패턴은 위임과 합성을 통해 문제를 해결한다.

아직은 내용이 어려울 수 있으니 사진과 코드로 확인하자.

구조

사진 출처 : 인파님 블로그 - (전략(Strategy) 패턴 - 완벽 마스터하기)에 구조가 너무 잘 정리돼있어서 인용했다.

위 사진과 같이 전략 패턴은 소프트웨어 설계 원칙을 지킨다.

  • OCP 원칙 : Strategy 의 확장에 열려있고, 수정에 닫혀있으며
  • DIP 원칙 : Context는 xxStrategy와 같이 구현체가 아닌 인터페이스에 의존하며

예제 코드

interface OutStrategy{
    fun readyProcess()
}

class Context {
    fun out(outStrategy: OutStrategy) {
        println("일어난다.")
        outStrategy.readyProcess()
        println("나간다.")
    }
}

class WorkOutStrategy: OutStrategy {
    override fun readyProcess() {
        println("대충 씻는다.")
        println("대충 옷을 입는다.")
    }
}

class PlayOutStrategy: OutStrategy {
    override fun readyProcess() {
        println("노래를 부르며 씻는다.")
        println("화장도 한다.")
        println("퍼스널 컬러에 맞춰 옷을 꾸며입는다.")
    }
}
class StrategyTest {
    @Test
    fun outTest(){
        val workOutStrategy = WorkOutStrategy()
        val playOutStrategy = PlayOutStrategy()
        val context = Context()

        context.out(workOutStrategy)
        context.out(playOutStrategy)
    }
}
일어난다.
대충 씻는다.
대충 옷을 입는다.
나간다.

일어난다.
노래를 부르며 씻는다.
화장도 한다.
퍼스널 컬러에 맞춰 옷을 꾸며입는다.
나간다.

장단점

장점

  • 소프트웨어 설계 원칙을 지킨다.
  • 인터페이스로 만들어져 다중 상속이 가능하다.
  • 전략(알고리즘)의 변경이 유연하다.

단점

  • 추가적인 인터페이스(전략)과 클래스(컨텍스트)가 필요하여 복잡도가 올라간다.
  • 코드를 실행할 때마다 전략을 지정해주어야 한다.
  • 적절한 전략을 선택하기 위한 개발자의 이해도가 필요하다.

템플릿 콜백 패턴

템플릿 콜백 패턴은 GOF 패턴에서 얘기하는 디자인 패턴이 아니라,
단지 스프링에서 위의 전략패턴을 템플릿 콜백 패턴이라고 정의한다.

전략 패턴의 Context -> 템플릿
Strategy -> 콜백

스프링에서는 JdbcTemplate, RestTemplate, TransactionTemplate, RedisTemplate 처럼 다양한 템플릿 콜백 패턴이 사용된다.
스프링에서 이름에 XxxTemplate 가 있다면 템플릿 콜백 패턴으로 만들어져있다 생각하면 된다.

Reference

https://refactoring.guru/ko/design-patterns/template-method
https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%EC%A0%84%EB%9E%B5Strategy-%ED%8C%A8%ED%84%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90#%EC%A0%84%EB%9E%B5_%ED%8C%A8%ED%84%B4_%EA%B5%AC%EC%A1%B0
김영한 - 스프링 핵심 원리 고급편

profile
A fast learner.

0개의 댓글