반응형

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


어떤 작업을 처리하는 일부분을 서브 클래스로 캡슐화해 전체 일을 수행하는 구조는 바꾸지 않으면서 특정 단계에서 수행하는 내역을 바꾸는 패턴이다.


즉, 전체적으로는 동일하면서 부분적으로는 다른 구문으로 구성된 메서드의 코드 중복을 최소화 할 때 유용하다. 
다른 관점에서 보면 동일한 기능을 상위 클래스에서 정의하면서 확장/변화가 필요한 부분만 서브 클래스에서 구현할 수 있도록 한다. 

 

좀더 이야기 해보자면 알고리즘에 대한 Framework 정의를 통해 Subclass의 다양한 method calls를 이룬다.

실질적인 behavior은 하위 클래스에서 implement 하도록 만든다.

 

상위 클래스에서는 공통적, 하위 클래스에서는 다양하게 코딩을 한다.

즉, 확장적이고 공통적인건 상위 클래스에서 정의하고 그렇지 않은 것은 imterface로 하위 클래스에서 정의한다.

 

즉, Template method는 각 스텝이 method의 call로 진행된다.

(알고리즘의 큰 step를 정해주고 부가적인 것은 subclass가 해결하도록 하는 것이다.)

 

템플릿 메서드 패턴의 특징 하나의 클래스가 전체 알고리즘은 보호하고 진행 할 수 있다.(Framework 생성과 유사)

재사용을 통해 코드 중복을 없애고 새로운 객체가 나타나도 그에 특화된 것만 코딩을 하면 되는 특징이 있다.

 

 

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

 

 

AbstractClass
템플릿 메서드를 정의하는 클래스


하위 클래스에 공통 알고리즘을 정의하고 하위 클래스에서 구현될 기능을 primitive 메서드 등으로 정의하는 클래스이다.


ConcreteClass
물려받은 primitive 메서드 또는 hook 메서드를 구현하는 클래스

 

상위 클래스에 구현된 템플릿 메서드의 일반적인 알고리즘에서 하위 클래스에 적합하게 primitive 메서드 등을 오버라이드 하는 클래스이다.

 

 

템플릿 메서드 패턴 예제

 

아이스 아메리카노와 아이스 라떼를 만드는 법을 비교해보자.

(지극히 제 생각으로 만드는 것이고 일반 카페에서 만드는 방법과 다를 수 있습니다.)

 

아이스 아메리카노 아이스 라떼

1. 물을 끓인다.

2. 끓는 물에 에스프레소를 넣는다.

3. 얼음을 넣는다.

4. 시럽을 넣는다.

1. 물을 끓인다.

2. 끓는 물에 에스프레소를 넣는다

3. 얼음을 넣는다

4, 우유를 넣는다.

 

이를 한번 코딩해보자.

 

package TemplateMethodPattern;

public class IceAmericano {
	public void makeIceAmericano() {
		boilWater();
		putEspresso();
		putIce();
		putSyrup();
	}
	private void boilWater() {
		System.out.println("물을 끓인다.");
	}
	private void putEspresso() {
		System.out.println("끓는 물에 에스프레소를 넣는다.");
	}
	private void putIce() {
		System.out.println("얼음을 넣는다.");
	}
	private void putSyrup() {
		System.out.println("시럽을 넣는다.");
	}
}
package TemplateMethodPattern;

public class IceLatte {
	public void makeIceLatte() {
		boilWater();
		putEspresso();
		putIce();
		putMilk();
	}
	private void boilWater() {
		System.out.println("물을 끓인다.");
	}
	private void putEspresso() {
		System.out.println("끓는 물에 에스프레소를 넣는다.");
	}
	private void putIce() {
		System.out.println("얼음을 넣는다.");
	}
	private void putMilk() {
		System.out.println("우유를 넣는다.");
	}
}
package TemplateMethodPattern;

public class MakeCoffeeMain {
	public static void main(String[] args) {
		IceAmericano americano = new IceAmericano();
		IceLatte latte = new IceLatte();
		
		americano.makeIceAmericano();
		System.out.println("===");
		latte.makeIceLatte();
	}
	
}
물을 끓인다.
끓는 물에 에스프레소를 넣는다.
얼음을 넣는다.
시럽을 넣는다.
===
물을 끓인다.
끓는 물에 에스프레소를 넣는다.
얼음을 넣는다.
우유를 넣는다.

 

그런데 위의 코드는 중복되는 코드가 많다.

 

따라서 한번 추상화 시켜 클래스 다이어그램으로 나타내보자.

 

 

무언가 Coffee 클래스에 공통된 것을 두고, 상속을 통해 자식 클래스에서 마무리하면 될 것 같다.

 

하지만 여기서 makeCoffee를 한단계 더 추상화 할 수 있다.

 

 

하지만 여기서 한단계 더 추상화 할 수 있다.

 

putSyrup, putMilk마저 putExtra로 추상화 하는 것이 템플릿 메소드 패턴의 목적이다.

 

이를 코드로 나타내면 아래와 같다.

 

 

Coffee 추상 클래스

아래 주석을 통해 템플릿 메서드 패턴의 목적을 확인해보자.

package TemplateMethodPattern;

public abstract class Coffee {
	final void makeCoffee() {
		boilWater();
		putEspresso();
		putIce();
		putExtra();
	}
	
	// SubClass에게 확장/변화가 필요한 코드만 코딩하도록 한다.
	abstract void putExtra();
	
	// 공통된 부분은 상위 클래스에서 해결하여 코드 중복을 최소화 시킨다.
	private void boilWater() {
		System.out.println("물을 끓인다.");		
	}
	private void putEspresso() {
		System.out.println("끓는 물에 에스프레소를 넣는다.");		
	}
	private void putIce() {
		System.out.println("얼음을 넣는다.");		
	}
}

 

 

IceAmericano 클래스

상속을 통해 공통된 부분은 받고 추상화된 메서드를 오버라이딩하여 자신의 방식으로 변형한다.

package TemplateMethodPattern;

public class IceAmericano extends Coffee{
	@Override
	void putExtra() {
		System.out.println("시럽을 넣는다.");		
	}
}

 

 

IceAmericano 클래스

상속을 통해 공통된 부분은 받고 추상화된 메서드를 오버라이딩하여 자신의 방식으로 변형한다.

package TemplateMethodPattern;

public class IceLatte extends Coffee{
	@Override 
	void putExtra() {
		System.out.println("우유를 넣는다.");
	}
}

 

CoffeeMain 클래스

확실히 템플릿 메서드 패턴을 접목하니 위의 코드보다 개선이 되었음을 알 수 있다.

package TemplateMethodPattern;

public class CoffeeMain {
	public static void main(String[] args) {
		IceAmericano americano = new IceAmericano();
		IceLatte latte = new IceLatte();
		
		americano.makeCoffee();
		System.out.println("===");
		latte.makeCoffee();
	}
	
}

 

물을 끓인다.
끓는 물에 에스프레소를 넣는다.
얼음을 넣는다.
시럽을 넣는다.
===
물을 끓인다.
끓는 물에 에스프레소를 넣는다.
얼음을 넣는다.
우유를 넣는다.

 

정리

 

템플릿 메소드 패턴은 "알고리즘의 뼈대"를 맞추는 것에 있다. 

즉, 전체적인 레이아웃을 통일 시키지만 상속받은 클래스로 하여금 어느정도 유연성을 주도록하는 디자인 패턴이다. 

추상 메소드(abstrcat method)와 훅 메소드(hook method)를 적절히 사용해서 

전체적인 알고리즘의 뼈대를 유지하되 유연하게 기능을 변경할 수 있도록 하고자 할 때 사용하면 유용하다.

반응형