본문 바로가기

Design Pattern

[Design Pattern] 템플릿 메서드 패턴(Template Method Pattern)

 

템플릿 메서드 패턴(Template Method Pattern) 은 소프트웨어 공학에서 동작 상의 알고리즘의 프로그램 뼈대를 정의하는 행위 디자인 패턴이다. 알고리즘의 구조를 변경하지 않고 알고리즘의 특정 단계들을 다시 정의할 수 있게 해준다.

 

상위 클래스 쪽에 템플릿에 해당하는 메서드가 정의되어 있고, 그 메서드의 정의 안에는 추상 메서드가 사용되고 있다.

추상 메서드를 실제로 구현하는 것은 하위 클래스이며, 하위 클래스에서 메서드를 구현하면 구체적인 처리가 결정된다.

 

그러나 어떤 하위 클래스에서 어떤 구현을 하더라도 처리의 큰 흐름은 상위 클래스에서 결정한대로 이루어지게 된다.

이와 같이 상위 클래스에서 처리의 뼈대를 결정하고, 하위 클래스에서 그 구체적인 내용을 결정하는 디자인 패턴템플릿 메서드 패턴(Template Method Pattern)이라고 한다.

 

 

https://upload.wikimedia.org/wikipedia/commons/2/2a/Template_Method_UML_class_diagram.svg

Template method pattern diagram

 

 

# Template method pattern

  • 상속을 통해 기능을 확장하는 패턴
  • 구체적인 것은 하위클래스에서 처리하도록 하는 구조
  • 상속을 통해 슈퍼클래스의 기능을 확장할 때 사용하는 대표적인 방법
  • 어떤 알고리즘에 대한 큰 틀이 결정된 상태에서 구체적인 설계를 서브클래스에 맡기는 디자인 패턴
  • 상위클래스(템플릿)에 기본적인 로직의 흐름 구성, 그 일부를 추상 메서드·protected 메서드로 기술하여, 서브클래스에서 구현·오버라이딩 하도록 하는 패턴
  • 스프링 프레임워크 등 프레임워크에서 주로 사용되는 구조

 

 


https://img1.daumcdn.net/thumb/R720x0.q80/?scode=mtistory2&fname=http%3A%2F%2Fcfile5.uf.tistory.com%2Fimage%2F2126F13B5313F4B814C159

라면은 정답입니다. ━_━)乃

 

 

일주일에 1~2번은 꼭 먹게되는 음식. 외로운 자취생들뿐만 아니라 대한민국 국민 모두에게 라면은 정답입니다.

라면이라는 Abstract Class(추상 클래스) 와 핫!하고 착한 기업! 갓뚜기의 진짬뽕, 진짜장으로 Concrete Class(구체 클래스)템플릿 메서드 패턴(Template Method Pattern)을 공부해보자.

 


 

 

1. Common Abstract Class(공통 추상 클래스)

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
package com.acma.pattern.lamen;
 
import lombok.extern.slf4j.Slf4j;
 
@Slf4j
public abstract class 라면 {
 
    // Template Method
    public void 라면을끓이자() {
        
        라면을준비한다();
        물이필요해();
        면을넣는다();
        물을버린다();
        log.info("스프를 넣는다.");
        먹는다();
    }
    
    
    // final keyword 로 수정불가
    final void 물이필요해() {
        log.info("냄비에 물을 적당히 채운다.");
    }
    
    
    // Abstract Method
    abstract void 라면을준비한다();
    
    
    // Hook Method
    void 물을버린다() {
        
    }
    
    // Hook Method
    void 면을넣는다() {
        log.info("물이 끓으면 면을 넣는다.");
    }
    
    // Hook Method
    void 먹는다() {
        log.info("꼬들꼬들 맛있는 라면~ 냠냠!! 하고 먹는다.");
    }
}
Colored by Color Scripter
 
  • 추상클래스 안에 추상메서드를 선언하고 일반메서드를 구현하였다.
  • 16 Line : 일반메서드로 처리할 수 있으나 "라면을끓이자" 라는 Template Method 에는 method 만 사용해야 하는게 아니라는 것을 보여주기 위한...(변명임...그냥 의미없이 코딩하였다...⊙_⊙;;;)
  • 21-23 Line : 라면(추상)클래스를 상속받는 클래스에서 수정할 수 없도록 Final Keyword를 사용하였다.
  • 27 Line : 라면(추상)클래스를 상속받는 구체클래스에 강제로 오버라이딩 시켜서 재정의 해야하는 추상메서드이다.
  • 31 Line : 일반메서드이며 구체클래스에서 재정의를 해도 되고 안해도 되는 메서드이다. 보통 Hook 메서드라고 부른다. Hook 메서드는 상황에 맞게 정의하거나 하지 않아도 된다.
  • 36-38 Line : 31 Line 과 동일.
  • 41-43 Line : 31 Line 과 동일.

 

 

 

2. Concrete Class(구체 클래스)

 

진짬뽕 구체 클래스(진짬뽕 Concrete Class)

1
2
3
4
5
6
7
8
9
10
11
12
package com.acma.pattern.lamen;
 
import lombok.extern.slf4j.Slf4j;
 
@Slf4j
public class 진짬뽕 extends 라면 {
 
    @Override
    void 라면을준비한다() {
        log.info("갓뚜기 진짬뽕을 준비한다.");
    }
}
Colored by Color Scripter
 
  • 6 Line : 진짬뽕 클래스는 라면(추상) 클래스를 상속받고 있다.
  • 8-11 Line : 상속받은 라면(추상) 클래스에서 선언한 "라면을준비한다" 추상 메서드를 재정의하였다.
  • 상속받은 라면(추상) 클래스의 Hook Method 를 재정의하지 않아도 문제가 없음을 알 수 있다.

진짜장 구체 클래스(진짜장 Concrete Class)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.acma.pattern.lamen;
 
import lombok.extern.slf4j.Slf4j;
 
@Slf4j
public class 진짜장 extends 라면 {
 
    @Override
    void 라면을준비한다() {
        log.info("갓뚜기 진짜장을 준비한다.");
    }
    
    
    // Hook Method of 라면
    void 물을버린다() {
        log.info("액체스프를 비빌수 있는 양의 물만 남기고 물을 버린다.");
    }
}
Colored by Color Scripter
 
  • 6 Line : 진짜장 클래스는 라면(추상) 클래스를 상속받고 있다.
  • 8-11 Line : 상속받은 라면(추상) 클래스에서 선언한 "라면을준비한다" 추상 메서드를 재정의하였다.
  • 15-17 Line : 라면(추상) 클래스에 구현된 "물을버린다" 메서드를 진짜장(구체) 클래스에서 재정의 하였다.

※ 진짬뽕과 진짜장 구체 클래스를 보면 알 수 있듯이 "abstract" 키워드를 붙이면 추상 클래스를 상속받은 구체 클래스는 반드시 해당 메서드를 구현해야 하지만 "abstract" 키워드를 붙이지 않고 Hook 메서드로 만들면 반드시 구현할 필요가 없다는 것을 알 수 있다. 즉 Hook 메서드는 상속 받은 클래스에서 선택적으로 오버라이드할 수 있다는 것을 알 수 있다.

 

 

 

3. 실행

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.acma.pattern;
 
import org.junit.Test;
 
import com.acma.pattern.lamen.진짜장;
import com.acma.pattern.lamen.진짬뽕;
 
import lombok.extern.slf4j.Slf4j;
 
@Slf4j
public class 템플릿메서드패턴테스트 {
 
    @Test
    public void 테스트() {
        
        log.info("============================== [ 진짬뽕 ]");
        진짬뽕 짬뽕라면 = new 진짬뽕();
        짬뽕라면.라면을끓이자();
        
        log.info("============================== [ 진짜장 ]");
        진짜장 짜장라면 = new 진짜장();
        짜장라면.라면을끓이자();
    }
}
Colored by Color Scripter
 
  • 13 Line : main 패키지의 main 메서드에서 실행할 수도 있지만 필자는 test 패키지에서 Junit Test 를 통해 코드를 실행하는 것을 선호한다.

 

 

 

4. 결과

진짬뽕과 진짜장의 실행 결과이다.

  • 진짬뽕의 경우 라면(추상) 클래스의 추상 메서드만 재정의하였다.
  • 진짜장의 경우 라면(추상) 클래스의 추상 메서드와 Hook 메서드를 재정의하였다.

 

templateMethodPattern.zip
0.06MB

 

 

 

 

# 라면의 레시피는 본인의 취향에 따라 달라질 수 있다. 소스 코드의 경우도 개발자 본인의 취향에 따라 달라질 수 있다. 하지만 라면마다 추천하는 다양한 레시피가 있듯이 '소스 코드를 작성하는 다양한 방법에 대해서 알고 있다면 더 좋은 소스 코드가 나오지 않을까' 라는 생각을 하게된다.