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

헤드퍼스트 디자인패턴 정리 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)

템플릿 메소드 패턴

  • 알고리즘의 골격을 정의합니다. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의할 수도 있습니다.

© 2022. All rights reserved.