여기서 말하는 '템플릿'은 우리가 기존에 알고 있는 '틀', '골격'의 개념과 같다.

잘 알고 있기때문에 정의부터 정리해보겠다.


* Template Method Pattern :

메소드에서 알고리즘의 골격을 정의한다. 일부 단계는 서브클래스에서 구현하도록 할 수 있다.

템플릿 메소드를 이용하면 알고리즘의 구조는 그대로 유지하면서 

특정 단계만 서브 클래스에서 새로 정의하도록 할 수 있다.



클래스 다이어그램을 보고 이해해보자.


이 다이어그램 가지고는 조금 설명이 부족하다.

코드로 좀 더 자세히 살펴보자.

abstract class AbstractClass
{
  // SubClass 에서 템플릿을 건드리는 것을 방지하지 위해 final 선언
  final void templateMethod(){
    primitiveOperation1();
    primitiveOperation2();
    concreteOperation();
    hook();
  }

  abstract void primitiveOperation1();
  abstract void primitiveOperation2();

  // 오버라이드 불가
  final void concreteOperation(){
    // implementation here
  }

  void hook() { }
}


* 후크(hook) 란?

- 추상 클래스에서 선언되는 메소드지만 기본적인 내용(default)만 구현되어 있거나

아무 코드도 들어있지 않은 클래스 이다. 이렇게 하면 서브 클래스 입장에서는 

hook()를 오버라이드 하여 다양한 위치에서 알고리즘에 끼어들 수 있다.



설명은 다 했으나 일상에서의 예시로 이해해보자.

일반적으로 커피와 차를 타는 것의 방법은 매우 유사하다. (어디까지나 일반적이다, 예민해하지 말자)


커피 : 물 끓이기 -> 커피 우려내기 -> 컵에 붓기 -> 취향껏 우유나 설탕 첨가

차 : 물 끓이기 -> 차 우려내기 -> 컵에 붓기 -> 취향껏 레몬 등 첨가


이미 템플릿 메소드 패턴에 대해 이해했으니 어떻게 디자인 해야할 지 느낌이 온다.

다음은 책의 예제코드를 참고했다.


추상 클래스 : CaffeineBeverage

- 템플릿(prepareRecipe) : 

boilWater() -> brew() -> pourInCup() -> wantCondiments() ? addCondiments() : nothing

- 추상 메소드 : brew(), addCondiments()

- 구상 메소드 : boilWater(), pourInCup()

- hook : wantCondiments() { return false; // default }


서브 클래스1 : Coffee

- 추상 메소드 구현 : brew(), addCondiments()

- hook 오버라이드 : wantCondiments()


서브 클래스2 : Tea

- 추상 메소드 구현 : brew(), addCondiments()



* 헐리우드 원칙 (Hollywood Principle)

- 먼저 연락하지 마세요. 저희가 연락 드리겠습니다.


이 원칙을 활용하면 '의존성 부패(dependency rot)' 를 방지할 수 있다.

어떤 고수준 구성요소가 저수준 구성요소에 의존하고, 그 저수준 구성요소는 다시 고수준 구성요소에

의존하고, 그 고수준 구성요소는 다시 또 다른 구성요소에 의존하고, 그 다른 구성요소는 또 저수준

구성요소에 의존하는 것과 같은 식으로 의존성이 복잡하게 꼬여있는 것을 의존성 부패라 한다.


또한 저수준 구성요소에서 시스템에 접속을 할 수는 있지만 (컴퓨테이션에 참여할 수는 있지만),

언제 어떤 식으로 그 구성요소들을 사용할 지는 고수준 구성요소에서 결정하게 된다.

즉, 헐리우드 원칙과 같은 맥락이다.


- 위의 예제를 보면 알 수 있듯이 Template Method 패턴이 이 원칙을 활용한다는 것을 알 수 있다.

뿐만 아니라 Factory Method, Observer 패턴 등 여러 패턴에서도 이 원칙이 활용된다.



Q. '헐리우드 원칙'과 '의존성 뒤집기 원칙(Dependency Inversion Principle)'은 어떤 관계?

- 의존성 뒤집기 원칙

가능한 구상 클래스 사용을 줄이고 대신 추상화된 것을 사용해야 한다.

- 헐리우드 원칙

저수준 구성요소가 컴퓨테이션에 참여할 수 있으면서도 저수준과 고수준 계층 사이에

의존성을 만들지 않도록 프레임워크 또는 구성요소를 구축하기 위한 기법.


따라서 객체를 분리시킨다는 목표를 공유하고 있으나,

의존성 뒤집기 원칙이 훨씬 더 강하고 일반적인 내용을 담고 있다고 할 수 있다.


Q. 저수준 구성요소는 고수준 구성요소에 있는 메소드를 호출 할 수는 없나?

- 그런 건 아니다. 상속을 통해 호출하는 경우가 종종 있지만 저수준과 고수준 구성요소 사이에

확연하게 드러나는 순환 의존성만은 피하자 !



*  Template Method 패턴 vs. Strategy 패턴 vs. Factory Method 패턴

- Template Method 패턴

. 알고리즘의 개요를 정의해 알고리즘 구조 자체는 그대로 유지한다.

. 알고리즘의 일부 단계를 구현하는 것을 서브클래스에서 처리한다.

. 상속을 이용하기 때문에 코드의 재사용성이 좋아 코드 중복이 거의 없다.

- Strategy 패턴

. 일련의 알고리즘군(群)을 정의하고 그 알고리즘을 서로 바꿔가면서 쓸 수 있게 해준다.

. 바꿔 쓸 수 있는 행동을 캡슐화하고, 어떤 행동을 사용할 지는 서브클래스에 맡긴다.

. 상속과 객체 구성을 통해서 알고리즘 구현을 선택할 수 있게 해준다.

- Factory Method 패턴

. 어떤 구상 클래스를 생성할 지를 서브 클래스에서 결정한다.

. 특화된 Template Method 이다.



* 객체지향의 원칙 :

1) 바뀌는 부분은 캡슐화 한다.

2) 상속보다는 구성을 활용한다.

3) 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.

4) 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.

5) 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다(OCP).

6) 추상화된 것에 의존해라. 구상 클래스에 의존해서는 안 된다(의존성 뒤집기 법칙).

7) 친한 친구들하고만 이야기한다(최소 지식 원칙).

8) 먼저 연락하지 마세요. 저희가 연락 드리겠습니다(헐리우드 원칙).



* 이 장에서의 정리 :

- 템플릿 메소드가 들어있는 추상 클래스에서는 추상 메소드, 구상 메소드, 후크를 정의할 수 있다.

- 서브 클래스에서 템플릿 메소드에 정의된 알고리즘을 함부로 바꾸게 하고 싶지 않다면 final 로 선언하자. 

구상 메소드 역시 마찬가지이다.

- 후크(hook)는 추상클래스에 있는, 아무 일도 하지 않거나 기본 행동을 정의하는 메소드이다.

서브클래스에서 오버라이드 가능.

- 헐리우드 원칙에 의하면, 저수준 모듈을 언제 어떻게 호출할 지는 고수준 모듈에서 결정하는 게 좋다.



(이미지 출처 : http://www.cnblogs.com/zhuqiang/archive/2012/04/27/2474179.html)


by kelicia 2014. 5. 28. 02:06