[디자인패턴] 템플릿메서드패턴(Template Method Pattern)

고지훈·2021년 9월 24일
2

DesignPattern

목록 보기
7/16
post-thumbnail

템플릿메서드패턴(Template Method Pattern)

템플릿 메서드 패턴은 여러 클래스에서 공통으로 사용하는 메서드를 상위 클래스에서 정의하고, 하위 클래스마다 다르게 구현해야하는 세부적인 사항을 하위 클래스에서 구현하는 패턴을 말한다.

  1. 템플릿메서드 방식을 사용하면, 코드의 중복을 제거할 수 있다.(리팩토링)
  2. 다른 관점에서 보면 동일한 기능을 상위 클래스에서 정의하고 확장/변화가 필요한 부분은 하위 클래스에서 구현할 수 있도록 한다.
  3. 전체적인 알고리즘은 상위 클래스에서 구현하고 다른 부분은 하위 클래스에서 구현함으로써 전체적인 알고리즘 코드를 재사용하는데 유용하다.
  4. 행위(Behavioral)패턴의 하나
    • 객체나 클래스 사이의 알고리즘이나 책임 분배에 관련된 패턴
    • 한 객체가 혼자 수행할 수 없는 작업을 여러 개의 객체로 어떻게 분배하는지, 또 그렇게 하면서도 객체 사이의 결합도를 최소화하는 것에 중점을 둔다.
  5. 상위 클래스에서 정의하는 부분은 템플릿 메서드라 하고, 템플릿 메서드에서 하위 클래스마다 다르게 작성되어야 하는 일부분을 훅이라고 한다.

  • AbstractClass
    • 템플릿 메서드를 정의하는 클래스
    • 하위 클래스에 공통 알고리즘을 정의하고 하위 클래스에서 구현될 기능을 primitive메서드 또는 hook메서드로 정의하는 클래스
  • ConcreteClass
    • 물려받은 primitive메서드 또는 hook메서드를 구현하는 클래스
    • 상위 클래스에 구현된 템플릿 메서드의 일반적인 알고리즘에서 하위 클래스에 적합하게 primitive메서드나 hook메서드를 오버라이드하는 클래스

왜, 템플릿메서드패턴을 사용할까?

템플릿메서드의 필요성을 보여주기위한 예로, 아이스 아메리카노와 아이스 라떼 만드는 법을 코드로 구현해보자!

// IceAmericano.java
public class IceAmericano {
    public void makeIceAmericano() {
        putEspresso();
        putIce();
        putMilk();
    }

    private void putEspresso() {
        System.out.println("에스프레소를 넣는다.");
    }

    private void putIce() {
        System.out.println("얼음을 넣는다.");
    }

    private void putWater() {
        System.out.println("끓는 물을 넣는다.");
    }
}
// IceLatte.java
public class IceLatte {
	public void makeIceLatte() {
        putEspresso();
        putIce();
        putMilk();
    }
    
    private void putEspresso() {
    	System.out.println("에스프레소를 넣는다.");
    }
    
    private void putIce() {
    	System.out.println("얼음을 넣는다.");
    }
    
    private void putMilk() {
    	System.out.println("끓는 우유를 넣는다.");
    }
}
// MakeCoffee.java
public class MakeCoffee {
    public static void main(String args[]){
    	IceAmericano americano = new IceAmericano();
        IceLatte latte = new IceLatte();
        
        americano.makeIceAmericano();
        System.out.println("=======");
        latte.makeIceLatte();
    }
}

하지만 위 결과를 보면, 에스프레소를 넣는것과 얼음을 넣는다는 행위는 중복되고 있다. 중복 방지를 위해 템플릿메서드를 사용하자!


템플릿메서드패턴 구현

공통으로 작업하는 항목을 Coffee클래스에 정의하고, 상속을 통해 자식클래스에서 자세한 것을 정의하면 된다.

// Coffee.java
public abstract class Coffee {
    final void makeCoffee() {
        putEspresso();
        putIce();
        putExtra();
    }

    private void putEspresso() {
        System.out.println("에스프레소를 넣는다.");
    }

    private void putIce() {
        System.out.println("얼음을 넣는다.");
    }

    // 확장/변화가 필요한 코드이고, 용도에 맞게 상속받아 구현한다.
    private void putExtra();
}
// IceAmericano.java
public class IceAmericano extends Coffee {
    @Override
    private void putExtra() {
    	System.out.println("끓는 물을 넣는다.");
    }
}
// IceLatte.java
public class IceLatte extends Coffee {
	@Override
    private void putExtra() {
    	System.out.println("끓는 우유를 넣는다.");
    }
}
// Coffee.java
public class Coffee {
    public static void main(String args[]){
    	IceAmericano americano = new IceAmericano();
        IceLatte latte = new IceLatte();
        
        americano.makeIceAmericano();
        System.out.println("=======");
        latte.makeIceLatte();
    }
}

템플릿메서드패턴의 특징은 전체적인 레이아웃을 통일하지만, 상속받은 클래스로 하여금 유연성을 주도록 하는 디자인 패턴이다.

추상 메소드와 훅 메소드를 사용해서 전체적인 알고리즘을 유지하되 유연하게 기능을 변경할 때 사용한다.

profile
"계획에 따르기보다 변화에 대응하기를"

2개의 댓글

comment-user-thumbnail
2021년 9월 27일

아이스 아메리카노에 끓는물을 넣다니...!

1개의 답글