안녕하세요. 이번에는 템플릿 메소드에 대해 알아보려 합니다.
먼저 템플릿은 쉽게 말해 일정한 틀, 형식을 의미합니다.
붕어빵틀을 흔히 예로 드는데요.
이런식의 틀만 있을 때 내용물만 조금씩 변경 해주기만 하면 다양한 붕어빵을 만들 수 있을 겁니다.
또 나만의 붕어빵으로도 만들 수 있겠죠? ^_^
이 처럼 이번에 살펴볼 템플릿 메소드 패턴은 이러한 템플릿의 기능을 가진 패턴인데요.
상위 클래스 쪽에 템플릿에 해당하는 메소드가 정의되어 있고, 그 메소드의 정의 안에는 추상 메소드가 사용되고 있습니다.
그래서 상위 클래스의 프로그램만 보면 추상 메소드를 어떻게 호출 하고 있는지 알 수 있지만 그 추상 메소드가 어떤 처리가 수행 되는지는 알 수 없어요.
추상 메소드를 실제로 구현하는 것은 하위 클래스 인데요. 하위 클래스 측에서 메소드를 구현하면 구체적인 처리가 결정돼요.
서로 다른 하위 클래스가 서로 다른 구현을 실행하면 서로 다른 처리가 실행될 텐데요. 어떤 하위 클래스에서 어떤 구현을 하더라도
처리의 큰 흐름은 상위 클래스에서 결정한대로 이루어져요. 이 처럼 상위 클래스에서 처리의 뼈대를 결정하고, 하위 클래스에서 그 구체적인 내용을 결정하는 디자인 패턴이 오늘 살펴 볼 템플릿 메소드 패턴 이에요.
이제 예제 프로그램을 만들어 볼 것인데요. 문자나 문자열을 5회 반복해서 표기 해주는 프로그램을 만들어 봅시다.
클래스 다이어그램은 위와 같이 구성되어 있습니다.
먼저 AbstractDisplay 클래스를 작성해보죠.
이 클래스는 open, print, close, display라는 메소드를 가졌습니다. 여기에서 open, print, close는 추상 메소드이고,
display 메소드만 구현 되고 있어요. 그리고 이 메소드가 하는 일은 다음과 같은데요.
- open 메소드를 호출하기
- print 메소드를 5회 호출하기
- close 메소드를 호출하기
그러면 open, print, close의 각 메소드는 무엇을 하고 있는 걸까요?
AbstractDisplay 클래스를 보면 위 3가지 메소드는 추상 메소드이기 때문에 AbstractDisplay가 실제로 무엇을 하는지는 AbstractDisplay 클래스만 보고서는 알 수 없어요. 실제로 무엇을 하고있는지는 open, print, close를 구현하는 하위 클래스에게 맡기고 있죠.
package bami;
public abstract class AbstractDisplay {
public abstract void open();
public abstract void print();
public abstract void close();
public final void display() {
open();
for (int i = 0; i < 5; i++) {
print();
}
close();
}
}
먼저 AbstractDisplay 라는 추상 클래스 안에 하위 클래스에 구현을 맡기는 추상 메소드인 open(), print(), close()를 선언해 줍니다.
그 후 추상 클래스에서 구현되고 있는 display()를 호출 하여 그 안에서 open()을 호출해서 먼저 open()을 해준 뒤에
print()를 5번 반복하여 호출한 뒤, 반복이 끝나면 close()를 시켜줍니다.
그 다음은 CharDisplay 클래스를 작성해봅시다.
이 클래스는 하위 클래스의 하나인데요. 상위 클래스인 AbstractDisplay 클래스에서 추상 메소드였던 open, print, close가 모두 구현 되어 있어 이 클래스는 추상 클래스가 아니에요.
각 메소드들의 기능을 정의해볼까요?
- open - "(("을 표시 하는 메소드
- print - 생성자에서 주어진 문자를 표시 해주는 메소드
- close - "))"을 표시 하는 메소드
이 상태에서 display 메소드가 호출 될 때 ((Hello))라는 문자열이 표시되도록 해보죠!
package bami;
public class CharDisplay extends AbstractDisplay {
private char ch;
public CharDisplay(char ch) {
this.ch = ch;
}
public void open() {
System.out.print("((");
}
public void print() {
System.out.print(ch);
}
public void close() {
System.out.println("))");
}
}
이제 StirngDisplay 클래스를 작성해보겠습니다. 마찬가지로 open, print, close가 구현되고 있는데요.
이번에는 위의 메소드가 어떤 처리가 되도록 만들어 볼까요? 어떤 칸안에 문자가 출력되도록 해보죠.
그러면 위의 메소드는 아래와 같이 정의할 수 있는데요.
- open - "*-----*"을 표시해주는 메소드
- print - 생성자에서 받은 문자열과 문자열 사이에 "|"를 표시해주는 메소드
- close - "*-----*"을 표시해주는 메소드
package bami;
public class StringDisplay extends AbstractDisplay {
private String str;
private int width;
public StringDisplay(String str) {
this.str = str;
this.width = str.getBytes().length;
}
public void open() {
printLine();
}
public void print() {
System.out.println("|" + str + "|");
}
public void close() {
printLine();
}
private void printLine() {
System.out.print("*");
for (int i = 0; i < width; i++) {
System.out.print("-");
}
System.out.println("*");
}
}
먼저 표시해야 할 문자열을 가지고 있는 str을 선언해주고, 바이트 단위로 계산한 문자열의 길이를 가지고 있는
width 변수를 선언해주었습니다.
그 다음 생성자에서 전달된 문자열 str을 필드와 바이트 단위의 길이의 필드에 저장해놓고 나중에 사용하도록 했습니다.
그 다음 오버라이드해서 정의한 open 메소드를 선언 해주는데요. 선을 그려주는 printLine()을 가지게 됩니다.
print 메소드는 생성자에서 받아온 문자열 사이에 "|"을붙여서 표시해주도록 했고,
close 메소드는 open 메소드와 마찬가지로 선을 그려주는 printLine()을 가지게 됩니다.
이제 Main 클래스를 만들어보죠! 여기에서 동작 테스트를 실행해줄 것인데요. 지금까지 만들었던 메소드들을 호출해보죠.
package bami;
public class Main {
public static void main(String[] args) {
AbstractDisplay display1 = new CharDisplay('B');
AbstractDisplay display2 = new StringDisplay("Hello, Bami.");
AbstractDisplay display3 = new StringDisplay("안녕 바미.");
display1.display();
display2.display();
display3.display();
}
}
먼저 'B'를 가진 1개의 CharDisplay 인스턴스와 각 문자열들을 가진 StringDisplay 인스턴스2개를 만들어줍니다.
그리고 display1 ~ 3모두 같은 AbstractDisplay의 하위 클래스의 인스턴스이기 때문에 상속한 display 메소드를 호출 할 수 있스빈다.
실제 동작은 CharDisplay와 StringDisplay에서 결정합니다.
이제 실행시켜보죠!
참고 : Java 언어로 배우는 디자인 패턴 입문
'프로그래밍(Basic) > 디자인 패턴(Java)' 카테고리의 다른 글
[바미] Singleton 패턴에 대해 알아봅시다. (0) | 2021.09.23 |
---|---|
[바미] Factory Method에 대해 알아봅시다. (0) | 2021.09.21 |
[바미] Adapter 패턴에 대해 알아봅시다. (0) | 2021.08.24 |
[바미] Iterator패턴에 대해 알아봅시다. (0) | 2021.08.17 |
[바미] UML에 대해 알아봅시다. (0) | 2021.08.16 |