top bar

글 목록

2014년 7월 9일 수요일

템플릿 메서드 패턴 (template method pattern) 1

템플릿 메소드 패턴을 한마디로 정의하자면
'알고리즘의 캡슐화' 라고한다. 잠깐, '전략 패턴'에도 알고리즘의 캡슐화라는 말을 사용했었 던것 같다. 하지만 무슨 차이가 있을까?

아래 Coffe 클래스가 있다

prepareRecipe 라는 메소드에는 '레시피'인 만큼 커피를 만드는 법(메서드)들이
순서대로 나열되어 있다.

또 아래는 Tea 클래스이다


마찬가지로 prepareRecipe 안에 차를 만드는 메서드들이 나열되어있다.

Coffee와 Tea 이 두가지 클래스는 매우 유사하다. 코드의 중복도 보인다.
딱 눈에 띄는것은 물을 끓이는 boilWater메서드와 컵에 따르는 pourInCup 메서드이다.
이러한 공통적인 메서드를 수퍼클래스로 끌어올리고 prepareReceipe는 수퍼클래스에서
추상 메서드로 선언해보자

그러한 작업을 거치면 1차적으로 아래와 같이 추상화를 할 수 있다.

추상화를 적용한 UML 다이어그램

하지만 이것으로 끝난 것일까? Coffe와 Tea의 메서드들을 가만히 보자.

먼저 brewCoffeCrinds 메서드와 steepTeaBag 메서드는 따지고보면 같다. 커피를 우려내는 것과 티백을 물에 넣어서 홍차를 우려내는 것은 어쨌든 '우려내는' 것은 똑같다.

addSugarAndMilk 메서드와 addLemon 메서드도 마찬가지다. 음료에 무언가를 '추가(add)' 하는것은 똑같지 않은가? 이제 서브 클래스에서 prepareReceipe 메서드를 일일히 구현할 필요없이 추상화 할수 있게 될것 같다.

위의 공통점을 묶어서 수퍼클래스인 CaffeineBeverage 클래스를 재구성하면 다음과 같다.


일단 음료를 '우려내는' brew 메서드를 선언했다. 물론 우려내는 동작은 다르므로 서브클래스에서 구현할 수 있게 추상메서드로 선언했다. 음료에 무언가를 '추가하는' addCondiments도 같은 논리로 추상메서드로 선언하였다.

이렇게 되면 Coffee와 Tea 클래스에는 brew 메서드와 addCondiments 메서드만 용도에 맞게 구현하면 되므로 아래와 같이 간략 해질 것이다.


최종적인 UML 다이어그램은 아래와 같다.

템플릿 메서드 패턴을 적용한 UML 다이어그램


이것이 바로 템플릿 메서드 패턴의 기본이다. 정확히 정리 해야 하기때문에 아래의
prepareReceipe 메서드를 살펴보자.

final void prepareReceipe() {
    boilWater();
    brew();
    pourInCup();
    addCondiments();
}

커피를 만들던, 차를 만들던 우리는 이 prepareReceipe 메서드를 가지고 만들 수 있다.
각각 CaffeineBeverage 클래스를 상속받은 구상클래스의 인스턴스를 생성하여, prepareReceipe 메서드를 호출해주면 된다. 바로 prepareReceipe 메서드가 틀(template)의 역할을 하는것이다.

다음과 같다.

ea myTea = new Tea();
myTea.prepareReceipe();

각각 서브클래스의 인스턴스로 자신이 상속한 수퍼클래스의 템플릿인 prepareReceipe 메서드를 호출하여 음료를 만들어 낸다. 하지만 일부 단계 (brew, addCondiments) 는 서브클래스의 구현에 의존하는 것이다.

이것이 템플릿 메서드 패턴인데... 데체 무엇이 장점일까? 비교해보자

Legacy
Template Method Pattern
CoffeeTea가 각각 작업을 처리한다. 두 클래스에서 각자의 알고리즘을 수행
CaffeineBeverage 클래스에서 작업을 처리한다. 알고리즘을 혼자 독점하고 있다
CeffeTea에 중복된 코드가 있다
CaffeineBeverage 덕분에 서브클래스에서 코드를 재사용 할 수 있다.
알고리즘이 바뀌면 서브클래스를 일일이 열어서 고쳐야 한다
알고리즘은 한군데 모여있기 때문에 그 부분만 고치면 된다
클래스 구조상 새로운 음료를 추가하려면 꽤많은 비용이 든다
prepareReceipe 라는 프레임워크(템플릿)을 제공함으로써 새로운 음료를 추가해도 몇가지 메서드만 추가하면 된다
알고리즘에 대한 지식과 구현 방법이 여러 클래스에 분산되어 있다.
CaffeineBeverage 클래스에 알고리즘에 대한 지식이 집중되어 있으며 일부 구현만 서브 클래스에 의존한다.

.....

템플릿 메서드 패턴을 대규모 프로젝트에 적용한다면 유지보수의 봄이 찾아올것만 같다.

다시한번 정확히 정리해 보자

템플릿 메서드 패턴 : 메서드에서 알고리즘에 골격을 정의한다. 알고리즘의 여러 단계중 일부는 서브클래스에서 구현 할 수 있다. 템플릿 메서드를 이용하면 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의 할 수 있다.

일반화된 템플릿 메서드 패턴


, 처음에 언급한 '전략패턴' 과의 차이를 간단하게 고찰해본다면, 일단 전략 패턴은 각각의 행동(알고리즘) 나타내는 인터페이스를 구현하여 '()' 형성한다. 다음으로 객체지향의 대표적인 속성중 하나인 '다형성(Polymorphism)' 이용하여 실행시간에 캡슐화된 알고리즘을 바꿔가며 유연하게 사용할 있었던 패턴이었다.

따라서 '알고리즘의 캡슐화' 라는 면에서는 템플릿 메서드 패턴과 비슷하지만, 구현 방법은 전혀 다르다. 템플릿 메서드 패턴에서 말하는 알고리즘 이라는것은 앞의 예에서 보았듯 prepareReceipe 메서드와 같은 일종의 '틀'이다. 그 알고리즘 단계에서 유연하게 바뀔수 있는 부분을 서브클래스에 의존하는것 뿐이다.

전략패턴에서의 캡슐화는 핵심 로직을 캡슐화 하는것이고, 템플릿 메서드 패턴의 캡슐화는 일련의 알고리즘 단계들을 캡슐화 하는 것이다. 정리하고 보니 꽤 큰 차이가 있는것같다.

음.. 일단 다음으로 템플릿 메서드와 함께 사용되는 후크(Hook) 메서드라는것이 있다는데,
나중에 정리해야겠다.


댓글 없음:

댓글 쓰기