osul_world 2021. 12. 29. 20:35
728x90

템플릿 메소드 패턴


  • 알고리즘의 골격을 변경하지 않고 하위 클래스에서 알고리즘의 일부 단계를 재정의할 수 있도록 해줌

여러 클래스들이 비슷한 알고리즘 구조를 가지고있지만 서로 약간식 다른경우 AbstractClass로 골격을 만들어 ConcreteClass에서 재정의 하여 쓰도록 한다.

  • 상위 클래스의 탬플릿 메소드에 Concrete Method으로 알고리즘이 기술되어 있으므로 코드 중복을 줄일 수 있음, abstract , final 을 이용하여 하위 클래스가 할 수 있는 일을 제한할 수 있음

전략 패턴은 알고리즘 전체를 바꿀 때 사용

탬플릿 메소드 패턴은 알고리즘의 틀은 유지한 상태에서 하위 클래스에서 일부 단계만 구체화함

 

  • 템플릿 메소드 패턴 구조

image|

primitiveMethod = abstractMethod

AbstractClass에 알고리즘 골격을 정의한 Template 메소드가 구현되어있다.

AbstractClass(상위)를 상속받아 알고리즘에서 쓰이는 메서드들을 ConcreteClass(하위)에서 구체화한다.

같은 알고리즘 골격이지만 기능이 약간씩 다른 경우 활용할수있다.

 

Template 메소드 패턴 구성

//AbstractClass: Template 메소드가 구현된 최상위 추상 클래스

public abstract class CaffeineBeverage{
    
     //Concrete Method: public final , private: 하위 재정의 불가
    public final void prepareRecipe(){ //<-Template 메소드:알고리즘 골격 정의
    boilWater();
    brew();
    pourInCup();
    if(customerWantsCondiments())
    	addCondiments();
    }
    
    //Abstract Method: protected, public: 하위 필수적 재정의 : 알고리즘에 쓰이는 메서드들 하위 클래스에게 정의 위임
    protected abstract void boilWater();
    protected abstract void brew(); 
    protected abstract void pourInCup(); 
    protected abstract void addCondiments(); 
    
    //Hook Method: protected, public: 하위 선택적 재정의 : 상위에 정의해두고 하위에서 선택적으로 재정의하도록 함
    public boolean customerWantsCondiments(){ 
    	return true;
    }
}

템플릿 메서드 패턴은 다음 3가지 메서드를 활용한다.

Concrete Method: Template 메소드가 정의된 클래스에 완전히 정의되는 메소드로 하위 클래스에서는 재정의하지 않아야 하는 연산

Abstract Method: Template 메소드가 정의된 클래스에 선언만 되어 있는 추상 메소드로 하위 클래스에서 반드시 재정의하여야 하는 연산

Template 메소드 내에 abstract 메소드로 정의되는 단계가 너무 많으면 하위 클래스에게 부담될 수 있음

public 메소드가 아니라 내부적으로만 사용하는 메소드일 수 있음 자식에서 재정의해야 하는 경우에는 최소 protected로 설정되어 있어야 함

Hook Method: Template 메소드가 정의된 클래스에 기본 행동이 정의되어 있는 메소드로 하위 클래스에서 선택적으로 재정의할 수 있는 연산

하위 클래스에서 어떤 메소드를 반드시 구현해야 하는지 알 수 없음. 따라서 문서화가 매우 중요

알고리즘의 골격을 유지하고 하위 클래스에서 알고리즘의 일부 단계를 재정의할 수 있도록 해줌

 

//ConcreteClass01: AbstractClass를 구체화 하고있는 하위 클래스: 여러개가 존재한다.
public class Coffee extends CaffeineBeverage{
    Abstract Methods 필수 overriding..
   
    Hook Methods 선택적 overriding..
}

//ConcreteClass02 ... ConcreteClass n

알고리즘이 유사하지만 서로다른 다양한 자손(ConcreteClass)들을 구현 할수있다.

 

Client 적용

//Cafe: Template 메소드를 구현하고있는 클래스를 이용하여 클라이언트에게 기능을 제공하는 클래스
public class Cafe{
    private CaffeineBeverage cb=null;
    
    public void setCaffeineBeverage(CaffeineBeverage cb){  //적용할 하위 클래스를 주입
        this.cb = cb;
    }
    
    public void prepare(){
        if(cb!=null) cb.prepareRecipe();
    }
}
//Client(TestCode)
public static void main(String[] args) {
        Cafe cafe1 = new Cafe();
        cafe1.setCaffeineBeverage(new Coffee()); //AbstractClass에게 ConcreteClass 주입
        cafe.prepareRecipe(); //주입되는 ConcreteClass에 따라 AbstractClass의 Template method의 결과가 다르게 나온다.
}

 

효과

의존성 부패(dependency rot) 문제를 방지할 수 있음 의존성 부패는 상위 수준 요소가 하위 수준 요소에 의존하고 이 하위 수준 요소가 다시 상위 수준 요소에 의존하는 등 의존 관계가 복잡하고 꼬여 있는 경우를 말함: 양방향 의존관계

상위, 하위 수준 요소는 무조건 상속 관계를 말하는 것은 아님 Has-a 관계에서도 상위 하위 가 있다.

구체적인 기능을 수행하면 하위 수준 요소라고 한다. : DI될 구체 클래스는 하위수준요소

하위 수준 요소들을 이용하여 기능을 수행하면 상위 수준 요소라고 한다. : has-a 보유 클래스는 상위 수준

 

Applicability

메소드를 위한 골격을 제공하여 자식 클래스들이 메소드의 특정 부분들만 재정의하도록 해야 할 때

모든 자식 클래스에 공통적으로 정의되는 메소드이지만 약간씩 차이가 있는 경우

자식 클래스가 반드시 재정의해야 하는 메소드를 제어하기 위해

 

이점

상위 클래스의 탬플릿 메소드에 알고리즘이 기술되어 있으므로 코드 중복을 줄일 수 있음

하위 클래스가 할 수 있는 일을 제한할 수 있음

자식 클래스의 확장을 제한할 수 있음

 

단점

상속을 이용하기때문에 알고리즘의 고정된 골격에 의해 유연성이 떨어질 수 있음

is-a 관계 대신에 has-a 관계로 모델링할 수 있음 (전략 패턴 형태)

추상 메소드는 전략에 해당하는 객체 메소드를 호출하는 형태로 구현함

이 방법에서는 훅 메소드를 활용할 수 없음

하위 클래스 이름을 통한 구분이 가능하지 않음

 

전략 패턴과 비교

전략 패턴은 알고리즘 전체를 바꿀 때 사용

탬플릿 메소드 패턴은 알고리즘의 틀은 유지한 상태에서 하위 클래스에서 일부 단계를 구체화함

 

Factory 메소드 패턴

전형적인 template 메소드 패턴임 생성하는 부분만 추상 메소드임

728x90