본문 바로가기

옛글/번역본

프로그래밍 Design Pattern 이해하기 - 8 템플릿메소드패턴

반응형

템플릿 메소드 패턴 (Encapsulating Algorithms - 알고리즘의 캡슐화)


커피없이 못사는 사람들이 있다. 그러나 몇몇 사람들은 차 없이 못산다. 그것들의 공통점은 뭘까?

바로 카페인이다!


티와 커피는 만들어지는 방법이 유사하다. 다음을 보자!






스타버즈 바리스타 트레이닝 메뉴얼이다. 

커피를 만드는 방법

- 물을 붓는다 

- 커피를 뜨거운 물에 붓는다

- 컵에 내린다

- 설탕과 커피를 넣는다. 


차를 만드는 방법

- 물을 붓는다

- 차를 뜨거운 물에 넣는다

- 컵에 붓는다

- 레몬을 첨가한다


Coffee 와 Tea Class들을 보자

"coding baristar"를 해보자! 커피와 차를 만드는 코드들을 작성해본다. 




이번엔 차를 만드는 클래스다



BeverageTest.java 를 보자




자 그런데 곰곰히 보니 두 클래스가 중복되는 것이 느껴진다. CaffeineBeverage로 두 클래스를 서브클래싱해보자!



즉, 


Coffee 에는

void prepare() {

boilWater();

brewCoffeeGrinds();

pourInCup();

addSugarAndMil();

}


Tea에는

void prepare(){

bowilWater();

steepTeaBag();

pourInCup();

addLemen();

}


bowilWater()과 pourInCup() 의 경우 둘다 같다!

그럼 좀 더 통용적인 표현으로 변경해보자


void prepare(){

boilWater();

brew();

pourInCup();

addCondiments();

}


CaffeineBevarage.java 를 보자 




prepareRecipe()는 final로 선언해서 서브클래스들이 호출하지 못하도록 만들었다. 

그리고 공통되는 boilWater(), pourInCup() 알고리즘은 캡슐화를 통해 한 곳에서 호출이 되며, 각각 다른 것들만 abstract로 만들어 서브클래스에서 메서드를 작성할 수 있도록 만들었다. 





즉 템플릿 메소드 패턴을 알아보면, 


-알고리즘의 각 단계(method)들을 정의하고, 

- 그 중 공통된 것이 있고 다른 것이 잇을 경우 method를 subclass에 abstract로 만든다!


그렇다면, 차이점이 무엇일까?



Tea와 Coffee를 따로 

템플릿 메소드 패턴 적용 

 각자 알고리즘 수행

CaffeineBeverage에서 알고리즘을 독자적으로 수행 

중복된 코드가 존재 

subclass에서 코드를 재사용 

알고리즘이 바뀌면 subclass들을 함께 수정  

알고리즘이 한곳에 모여있으므로 수정에 닫힘  

새로운 음료를 추가하려면 많은 작업이 필요  

추가한 곳의 abstract메소드만 수정  

알고리즘이 여러 클래스에 구현  

알고리즘이 하나에 집중되어 있음  





AbstractClass에 모든 단계를 가진 method가 있고 각각의 단계를 method로 나눈다. 

그리고 ConcreateClass들에서 서브클래스를 통해 각각이 다른 메소드들을 구현한다. 


Hook 후크!


후크란 추상메소드에서 선언되는 메소드다. 아래 코드를 보자.



conditinal statement 를 넣었다. 이는 concreate class에 customerWantsCondiments의 boolean 값을 통해 고객이 첨가물을 원할 때에만 첨가물을 넣는 메서드를 실행시키도록 만들었다. 

여기서 후크는 boolean customerWantsCondiments()를 의미한다! (상위인 CaffeineBeverageWithHook 클래스에서는 빈 메서드만이 존재한다.)







이는 바로 이 "원칙(이론)"에 부합한다!


새로운 이론 바로 "헐리우드 이론"이다. 


간단하다! "연락하지마세요. 우리가 연락드리겠습니다" 의 의미를 가진다. 즉 상위의존성을 피할 수 있는 이론이다. 상위에 있는 컴포넌트가 로우 레벨의 컴퍼넌트(Concreate class)의 후크를 통해 결정을 내리도록 하기 때문이다. 


메소드패턴은 매우 통용적으로 많이 사용이 된다. 그리고 이 패턴은 매우 디자인이 잘된 프레임워크에서 보는 경우가 많다. 


자바에서 이 메소드패턴을 찾을 수 이쓴 ㄴ부분은 java.io의 InputStream에 있는 read()메소드이다. 

+Android 에서 Activity를 extends해서 쓸 때 라이프사이클에 해당하는 부분도 이 템플릿메소드 패턴턴에 해당한다. 


정리를 하면, 


- 알고리즘의 단계를 정의하는 일부 단계를 서브클래스에서 구현할 수 있도록 한다. 

- 코드를 재사용한다. 

- 템플릿 메소드가 들어있는 추상클래스는 구상 메소드, 추상 메솓, 후크를 가질 수 있다.

- 후크는 추상클래스내에서는 아무 일도 하지 않지만 서브클래에서 오버라이드할 수 있다.

- 스트래티지 패턴과 템플릿 패턴 둘다 공통점은 알고리즘을 캡슐화한다. (다른 점은 스트래티피 패턴은 상속을, 템플릿 패턴은 구성을 이용한다.)






반응형