Design Pattern

[Design Pattern] 템플릿 메소드 패턴

JiWonSon 2023. 3. 5. 09:59

1. 템플릿 메소드 패턴이란?

 알고리즘의 골격을 정의한다. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있으며, 알고리즘 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의할 수도 있다.

 

"알고리즘의 틀을 만들기 위한 패턴"

 

2. 예시

1) 커피와 홍차가 만들어지는 법 비교해보기

1. 커피 만드는 법

1) 물을 끓인다.

2) 끓는 물에 커피를 우려낸다.

3) 커피를 컵에 따른다.

4) 설탕과 우유를 추가한다.



2. 홍차 만드는 법

1) 물을 끓인다.

2) 끓는 물에 차를 우려낸다.

3) 차를 컵에 따른다.

4) 설탕을 추가한다.

여기서 음료를 준비하는 단계는 물 끓이기 → 우리기 → 컵에 붓기 → 첨가물 추가하기 순으로 이루어진다.

 

아래 클래스를 보자.

 

public class Coffee {

	void prepareRecipe() {

		boilWater();

		brewCoffeeGrinds();

		pourInCup();

		addSugarAndMilk();

	}

	public void boilWater() {

		System.out.println("물 끓이는 중");

	}

	public void breqCoffeeGrinds() {

		System.out.println("필터를 통해 커피를 우려내는 중");

	}

	public void pourInCup() {

		System.out.println("컵에 따르는 중");

	}

	public void addSugarAndMilk() {

		System.out.println("설탕과 우유를 추가하는 중");

	}

}
public class Tea {

	void prepareRecipe() {

		boilWater();

		steepTeaBag();

		pourInCup();

		addSugar();

	}

	public void boilWater() {

		System.out.println("물 끓이는 중");

	}

	public void steepTeaBag() {

		System.out.println("차를 우려내는 중");

	}

	public void pourInCup() {

		System.out.println("컵에 따르는 중");

	}

	public void addLemon() {

		System.out.println("설탕을 추가하는 중");

	}

}

코드가 중복되어 있다. 클래스가  거의 동일하니까, 공통 부분은 추상화 시켜 클래스를 만들어 보자.

 

 

알고리즘의 각 단계는 템플릿 메소드 안에서 메소드로 표현된다. 어떤 메소드는 이 클래스에서, 어떤 메소드는 서브클래스에서 처리되기도 하는데, 서브클래스에서 구현해야 하는 경우에는 메소드를 abstract로 선언하도록 한다.

 

총제적으로 본다면 서로 다른 메소드를 사용하지만, 둘은 서로 별로 다르지 않다.

 

템플릿 메소드 패턴을 적용해보자.

 

public abstract class CaffeineBeverage {

	final void prepareRecipe() {

		boilWater();

		brew();

		pourInCup();

		addcondiments();

	}

	abstract void brew();

	abstract void addcondiments();

	void boilWater() {

		System.out.println("물 끓이는 중");

	}

	void pourInCup() {

		System.out.println("컵에 따르는 중");

	}

}

 

public class Coffee extends CaffeineBeverage {

	@Override
	void brew() {

		System.out.println("필터를 통해 커피를 우려내는 중");

	}

	@Override
	public void addCondiments() {

		System.out.println("설탕과 우유를 추가하는 중");

	}

}

 

public class Tea extends CaffeineBeverage {

	@Override
	void brew() {

		System.out.println("차를 우려내는 중");

	}

	@Override
	public void addCondiments() {

		System.out.println("설탕을 추가하는 중");

	}

}

 

차를 만들어 보자!

 

1. Tea 객체를 만들고.

Tea myTea = new Tea();



2. 템플릿 메소드를 호출한다.

myTea.prepareRecipe(); 카페인 음료를 만들기 위한 알고리즘이 돌아간다.



3. 물을 끓인다.

boilWater(); 이 단계는 CaffeineBeverage 에서 처리된다.



4. 이제 차를 우려낸다. 

brew(); 이방법은 서브클래스만 알고있다.



5. 차를 컵에 따른다.

pourInCup(); 이 단계도 공통적인 부분이기 때문에 Caffeinebeverage 에서 맡아서 처리된다.



6. 마지막으로 첨가물을 추가한다.

addCondiments(); 첨가물은 음료마다 다르기때문에 서브클래스에서 처리된다.

 

위와 같이 템플릿 메소드 패턴에서는 알고리즘의 각 단계들을 정의하고, 그 중 몇 개는 서브클래스에 의해 알고리즘을 구체화하여 제공한다.

 

3. 후크(hook) ?

추상 클래스에서 선언된, 아무 코드도 들어가지 않은 메소드이다. 필요한 경우에만 구현 클래스에서 오버라이드해 입맛에 맞게 수정할 수 있다.

 

public abstract class CaffeinBeverageWithHook {
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();        
        }
    }
    
    abstract void brew();
    
    abstract void addCondiments();
    
    void boilWater() {
        // ...
    }
    
    void pourInCup() {
        // ...
    }
    
    // 이 메소드가 서브클래스에서 필요에 따라 오버라이드할 수 있는 메소드 이므로 "후크"임
    boolean customerWantsCondiments() {
        return true;
    }
}

 prepareRecipe에서 손님이 첨가물을 넣어 달라고 했을 때만 (customerWantsCondiments가 true를 리턴할 때만) 첨가물을 추가하도록 코드를 수정했다. customerWantsCondiments는 true만 리턴하는 기본적인 후크 메소드이다. customerWantsCondiments는 필요한 경우에만 서브클래스에서 오버라이드해 첨가물을 추가할지 여부를 입력받는 코드로 수정하여 사용할 수 있다.

 

 

4. 후크와 추상 메소드

추상 메소드  서브클래스가 알고리즘 특정 단계를 반드시 제공해야 할 때

후크  서브클래스가 알고리즘 특정 단계를 선택적으로 제공해야 할 때

 

'Design Pattern' 카테고리의 다른 글

[Design Pttern] 데코레이터 패턴  (2) 2023.02.05
[Design Pattern] MVC패턴  (0) 2023.01.09
[Design Patter] 상태패턴  (0) 2023.01.07
[Design Pattern] 싱글톤 패턴  (0) 2022.12.17