헤드퍼스트 디자인패턴 정리 08 - 템플릿 메소드 패턴

헤드퍼스트 디자인패턴 책을 읽으면서 주요 내용을 정리해놓은 노트를 공개합니다.
헤드퍼스트 디자인패턴 8장 템플릿 메소드 패턴에 대해 요약정리한 내용입니다.
메소드가 거의 일치하는 두 개의 클래스가 있다면, 물론 하나의 슈퍼클래스를 만들고 서브 클래스에서 구현하는 방법도 있겠지만… ‘일부만’ 일반화해서 Base클래스에서는 몇 가지만 직접 처리하고, 몇 가지는 서브클래스에 의존하게 만들 수도 있다.
템플릿 메소드 패턴
public abstract class AbstractClass
{
// 서브클래스가 알고리즘의 각 단계를 마음대로 건드리지 못하게 sealed로 선언
public sealed void templateMethod()
{
primitiveOperation1();
primitiveOperation2();
concreteOperation();
hook();
}
// 이하는 각기 다른 구현이므로 서브클래스에서 구현
protected abstract void primitiveOperation1();
protected abstract void primitiveOperation2();
// 이하는 공통된 부분이므로 직접 구현
public sealed void concreteOperation()
{
// sealed로 선언되었으므로 서브클래스에서 오버라이드 불가
// 템플릿 메소드에서 직접 호출하거나 서브클래스에서 호출가능
// ...
}
// 아무것도 하지 않는 구상 메소드 = 후크
// 서브클래스에서 오버라이드 할 수도 있지만 반드시 그래야하는 건 아님
protected void hook() {}
}
장점
- 서브클래스에서 코드를 재사용 가능
- 한 군데에 알고리즘이 모여있으므로 한 부분만 고치면 됨
- 다른 음료도 쉽게 추가할 수 있는 프레임워크 역할
- 일부 구현만 서브클래스에 의존
[!템플릿 메소드 패턴] 알고리즘의 골격을 정의합니다. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의할 수도 있습니다.
즉… 여러 단계 가운데 하나 이상의 단계가 추상메소드로 정의되며, 그 추상메소드는 서브클래스에서 구현됨.
후크 hook
추상 클래스에서 선언되지만 기본적인 내용만 구현되어있거나, 아무 코드도 들어있지 않은 메소드. => 이러면 서브클래스는 다양한 위치에서 알고리즘에 끼어들 수도 있고, 무시할 수도 있다.
사용 시, 서브클래스에서 후크를 오버라이드. 예를들어 다음과 같이 사용 가능하다.
public abstract class CaffeinBeverageWithHook()
{
sealed void preparedRecipe()
{
boilWater();
brew();
pourInCup();
if(customerWantsCondiments())
{
addCondiments();
}
}
// (다른 메소드들 생략)
public abstract void addCondiments();
// 서브클래스에서 필요할 때 오버라이드하는 hook메소드
public virtual bool customerWantsCondiments()
{
return true;
}
}
추상메소드와 후크의 사용
- 추상메소드: 서브클래스가 알고리즘의 특정 단계를 제공해야할 때 (필수)
- 후크: 알고리즘의 특정 단계가 선택적으로 적용될 때 (선택적)
할리우드 원칙
‘먼저 연락하지 마세요. 저희가 연락 드리겠습니다.’
- 의존성 부패(dependency rot)를 방지할 수 있다.
- 의존성 부패? 고수준 구성요소가 저수준 구성요소에 의존하고, 그 저수준 구성요소는 다시 고수준 구성 요소에 의존하고.. 그리고…
- 즉, 저수준 구성요소가 시스템에 접속할 수는 있지만 언제 어떻게 그 구성 요소를 사용할지는 고수준 구성 요소가 결정.
의존성 뒤집기 원칙과의 관계
- 할리우드 원칙은 저수준 구성요소가 컴퓨테이션에 참여하면서도 저수준 구성 요소와 고수준 계층 간 의존을 없애도록 프레임워크나 구성요소를 구축하는 기법
- 의존성 뒤집기 원칙은 될 수 있으면 구상 클래스 사용을 줄이고 추상화된 것을 사용해야한다는 원칙 => 의존성 뒤집기 원칙이 훨씬 강하고 일반적인 애용을 담고 있다. 물론 두 원칙은 객체를 분리한다는 하나의 목표를 공유한다.
헷깔릴 수 있는 부분 정리
- 템플릿 메소드 패턴: 알고리즘의 어떤 단계를 구현하는 방법을 서브클래스에서 결정
- 알고리즘의 개요를 정의. 진짜 작업 중 일부는 서브클래스가 처리.(알고리즘의 구조 유지)
- 전략패턴: 바꿔 쓸 수 있는 행동을 캡슐화하고 어떤 행동을 사용할지는 서브클래스에 맡긴다
- 일련의 알고리즘군을 정의하고 그 알고리즘들을 서로 바꿔가면서 쓸 수 있게 해줌
- 팩토리 메소드 패턴: 구상 클래스의 인스턴스 생성을 서브클래스에서 결정
- 특화된 템플릿 메소드 패턴
마무리
객체지향 원칙
- 바뀌는 부분은 캡슐화한다
- 상속보다는 구성을 활용한다
- 구현보다는 인터페이스에 맞춰서 프로그래밍한다
- 상호작용하는 객체 사이에서는 가능하면 느슨한 결합을 사용해야한다
- 클래스는 확장에 열려 있어야 하지만 변경에는 닫혀 있어야 한다(OCP)
- 추상화된 것에 의존하게 만들고 구상 클래스에 의존하지 않게 만든다
- 진짜 절친에게만 이야기해야한다 = 최소결합 직접 알 필요가 없는 다른 객체와 상호작용하는 것을 피하라
- 저수준 구성요소가 시스템에 접속할 수는 있지만 언제 어떻게 그 구성 요소를 사용할지는 고수준 구성 요소가 결정한다 (순환의존 X)
템플릿 메소드 패턴
- 알고리즘의 골격을 정의합니다. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의할 수도 있습니다.