본문 바로가기

Programinng/Design Pattern

자바(Java) - Template Method Pattern 템플릿 메소드 패턴

템플릿 메소드 패턴이란, 알고리즘의 뼈대를 정의하고 그 알고리즘의 여러 단계 중 일부를 이를 Subclassing한 Subclass에서 재정의 할 수 있다. 


라면을 끓이는 동작 한 번 정의해 보자. 


1. 냄비를 올린다.

2. 물이 끓는다.

3. 라면을 조리한다.

4. 그릇에 담는다.


1,2,4은 모든 라면의 조리 방법이 같다. 하지만 3번은 너구리 라면을 넣는 다던지 삼양라면을 넣는 다던지 다르게 정의하겠다. 


일단, 공통적인 알고리즘을 Abstract class로 정의하고, Subclass에서 재정의 해서 사용할 method는 abstract method로 정의한다.

public abstract class Ramen { 
     
    public void make(){ 
        preparePot(); 
        boilWater(); 
        cooking(); 
        transferBowl(); 
    } 

    private void preparePot() { 
        System.out.println("냄비에 물을 올린다."); 
    } 
     
    private void boilWater() { 
        System.out.println("물이 끓는다."); 
    } 
     
    public abstract void cooking(); 
     
    private void transferBowl() { 
        System.out.println("그릇에 담는다."); 
    } 
}



그리고 이를 구현한 NuguriRamen와 SamyangRamen를 정의한다. abstract method인 cooking을 재정의 한다. 

public class NuguriRamen extends Ramen{ 
    @Override 
    public void cooking() { 
        System.out.println("너구리 라면을 넣고 조리한다."); 
    } 
}


public class SamyangRamen extends Ramen{ 
    @Override 
    public void cooking() { 
        System.out.println("삼양라면을 넣고 조리한다."); 
    } 
}


이제 테스트 한번 해보겠다.

Ramen nuguri = new NuguriRamen(); 
Ramen samyang = new SamyangRamen(); 

nuguri.make(); 
System.out.println("-----"); 
samyang.make();



- 결과

냄비에 물을 올린다.

물이 끓는다.

너구리 라면을 넣고 조리한다.

그릇에 담는다.

-----

냄비에 물을 올린다.

물이 끓는다.

삼양라면을 넣고 조리한다.

그릇에 담는다.




하지만, 문제가 있다. 짜파게티인 경우 라면을 조리하기전에 물을 버려야 한다. 이렇게 특수한 일을 처리해야 할 경우, hook를 사용해서 해결 할 수 있다.


일단 Ramen class를 다음과 같이 수정한다.

public abstract class Ramen { 
     
    public void make(){ 
        preparePot(); 
        boilWater(); 
        if(hook()){ 
            discardWater(); 
        } 
        cooking(); 
        transferBowl(); 
    } 


    private void preparePot() { 
        System.out.println("냄비에 물을 올린다."); 
    } 
     
    private void boilWater() { 
        System.out.println("물이 끓는다."); 
    } 
     
    protected boolean hook() { 
        return false
    } 
     
    private void discardWater() { 
        System.out.println("물을 버린다."); 
    } 
     
    public abstract void cooking(); 
     
    private void transferBowl() { 
        System.out.println("그릇에 담는다."); 
    } 
}


그리고 JjapagetyRamen를 구현할때 hook method를 override한다.

public class JjapagetyRamen extends Ramen{ 
    @Override 
    protected boolean hook() { 
        return true
    } 

    @Override 
    public void cooking() { 
        System.out.println("짜파게티를 넣고 조리한다."); 
    } 
}