포스트

[Behavioral Pattern] 템플릿 메소드 패턴 (Template Method Pattern)

Design Pattern / Behavioral Pattern

템플릿 메소드 패턴의 정의와 해당 디자인 패턴의 예제 코드를 통한 이해 및 설명 정리

개념

  • 여러 클래스에서 공통으로 사용하는 메서드를 템플릿화하여 상위 클래서에서 정의하고, 하위 클래스마다 세부 동작 사항을 다르게 구현하는 패턴

    • 즉, 변하지 않는 기능(템플릿)은 상위 클래스에 만들어두고, 자주 변경되며 확장할 기능은 하위 클래스에서 만들도록 하여 상위의 메소드 실행 동작 순서는 고정하면서, 세부 실행 내용은 다양화 될 수 있는 경우에 사용함
  • 템플릿 메소드 패턴은 상속이라는 기술을 극대화하여, 알고리즘의 뼈대를 맞추는 것에 초점을 둠

    • 이미 수많은 프레임워크에서 많은 부분에 템플릿 메소드 패턴 코드가 적용되어 있음

디자인 페턴에서의 템플릿은 변하지 않는다는 것을 의미

패턴 구조

teamplate_method

  • AbstractClass (추상 클래스)

    • 템플릿 메소드를 구현하고, 템플릿 메소드에서 돌아가는 추상 메소드를 선언함

    • 이 추상 메소드는 하위 클래스인 ConcreteClass 역할에 의해 구현됨

  • ConcreteClass (구현 클래스)

    • AbstractClass를 상속하고, 추상 메소드를를 구체적으로 구현함

    • ConcreteClass에서 구현한 메소드는 AbstractClass의 템플릿 메소드에서 호출

예제 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
abstract class AbstractClass {
  public templateMethod(): void {
    this.baseOperation_1();
    this.requireOperations_1();
    this.baseOperation_2();
    this.hook_1();
    this.requireOperations_2();
    this.baseOperation_3();
    this.hook_2();
  }

  protected baseOperation_1(): void {
    console.log("AbastractClass says: I'm doing the bulk of the work");
  }

  protected baseOperation_2(): void {
    console.log(
      "AbastractClass says: But I let subclasses override some operations"
    );
  }

  protected baseOperation_3(): void {
    console.log("AbastractClass says: I'm doing the bulk of the work");
  }

  protected abstract requireOperations_1(): void;
  protected abstract requireOperations_2(): void;

  protected hook_1(): void {}
  protected hook_2(): void {}
}

class ConcreteClass_1 extends AbstractClass {
  protected requireOperations_1(): void {
    console.log("ConcreteClass_1 says: Implemented Operation 1");
  }

  protected requireOperations_2(): void {
    console.log("ConcreteClass_1 says: Implemented Operation 2");
  }
}

class ConcreteClass_2 extends AbstractClass {
  protected requireOperations_1(): void {
    console.log("ConcreteClass_2 says: Implemented Operation 1");
  }

  protected requireOperations_2(): void {
    console.log("ConcreteClass_2 says: Implemented Operation 2");
  }

  protected hook_1(): void {
    console.log("ConcreteClass_2 says: Overridden Hook 1");
  }
}

function clientCode(abstractClass: AbstractClass) {
  abstractClass.templateMethod();
}

console.log("----------------------------------------------------------------");
console.log("Same client code can work with different subclasses:");
clientCode(new ConcreteClass_1());
console.log("");

console.log("Same client code can work with different subclasses:");
clientCode(new ConcreteClass_2());
console.log("----------------------------------------------------------------");

참고한 출처 사이트

Refactoring GURU

Inpa Dev Blog (디자인 패턴)

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.