템플릿 메서드(Template Method) 패턴이란 무엇인가?
복붙을 많이하는 프로그래밍의 특성상 코딩을 하다보면 아래의 예시처럼 동일한 코드가 특정한 부분을 빼고 똑같이 반복되는 결과물이 나온적이 한번씩 있을거라 생각합니다.
void method1() {
System.out.println("동일한 코드 A");
System.out.println("method1만의 코드");
System.out.println("동일한 코드 B");
}
void method2() {
System.out.println("동일한 코드 A");
System.out.println("method2만의 코드");
System.out.println("동일한 코드 B");
}
위와 같은 상황이 발생하는 경우 동일한 부분은 묶어서 따로 빼두고 변경 되는 부분만 재정의할 수 있게 작업하면 편하지 않을까란 생각에서 나오게된 패턴이 바로 템플릿 메서드 패턴입니다.
즉, 위 코드 중
void method() {
System.out.println("동일한 코드 A");
core();
System.out.println("동일한 코드 B");
}
위 부분에 해당하는 내용만 템플릿화 시켜서 상위 클래스로 구현하고 core()에 해당하는 내용은 해당 클래스를 상속 받은 서브클래스에서 구현되게하는 패턴인 것입니다.
템플릿 메서드(Template Method) 구현 해보기
라면을 끓이는걸 예시로 직접적인 예제 코드를 한번 작성해보겠습니다.
public abstract class Ramen {
public void CookRamen() {
// 공통적인 뼈대 로직
System.out.println("냄비를 꺼낸다.");
System.out.println("물을 담는다.");
System.out.println("불을 켠다.");
System.out.println("물이 끓는다.");
// 내부에서 구현될 상세 로직
putRamen();
// hook 연산
putMyRecipe();
}
protected abstract void putRamen();
// hook 연산
protected void putMyRecipe() {
// 정의만 하고 아무런 동작을 하지 않는다.
}
}
위 코드는 추상클래스로 작성하였으며, 라면을 끓일 때 공통적인 부분을 템플릿 화 하였고, 실질적으로 어떤 라면을 끓이느냐에 따라 달라지는 부분은 putRamen()
추상 메소드로 정의 하였습니다.
이제 Ramen 클래스를 상속받은 자식클래스들은 putRamen()
메소드만 구현하여, 공통된 기능을 쉽게 사용할 수 있게 되었습니다. 예시로 신라면과 안성탕면(제가 제일 좋아하는 라면:)을 예시로 두 개의 자식 클래스를 만들어 보겠습니다.
public class ShinRamen extends Ramen {
@Override
protected void putRamen() {
System.out.println("신라면을 넣는다.");
}
}
public class Anseongtangmyeon extends Ramen {
@Override
protected void putRamen() {
System.out.println("안성탕면을 넣는다.");
}
}
그리고 아래와 같이 Main을 만들어서 동작시켜 보면
public class RamenMain {
public static void main(String[] args) {
System.out.println("=====================================");
Ramen shinRamen = new ShinRamen();
shinRamen.CookRamen();
System.out.println("=====================================");
Ramen anseongtangmyeon = new Anseongtangmyeon();
anseongtangmyeon.CookRamen();
}
}
아래와 같이 정상적으로 동작하는것을 확인 할 수 있습니다.
훅(hook)은 뭐죠?
위의 Ramen 클래스를 보면 hook연산이란 주석과 함께 설명하지않았던 putMyRecipe()
라는 메소드가 추가되어있는걸 볼 수 있습니다. 이를 우리는 훅(hook) 연산이라 부르는데 필수적으로 구현해야 하는 putRamen()
메소드와는 달리 자식 클래스를 구현하는 사용자가 필요에 재정의를 할수 있는 선택적인 메소드입니다.
쉽게 말해, 기본적으로는 아무 동작도 하지 않지만, 서브클래스가 원하는 경우 지정된 시점에서 기능을 추가할 수 있도록 제공된 메서드입니다. 실제 사용을 위해서 Anseongtangmyeon 클래스의 코드를 바꿔 보겠습니다.
public class Anseongtangmyeon extends Ramen {
@Override
protected void putRamen() {
System.out.println("안성탕면을 넣는다.");
}
@Override
protected void putMyRecipe() {
System.out.println("안성탕면은 계란을 넣어야 맛있다!");
System.out.println("계란을 넣는다.");
}
}
이렇게 코드를 바꾸어 실행해 보면 정상적으로 코드가 동작하는것을 볼 수 있습니다.
주의할점
템플릿 메소드로 구현된 추상화 클래스를 효과적으로 사용하기위해선 서브클래스의 작성자는 어떤 연산들이 오버라이드용으로 설계되었는지를 제대로 파악하고 있어야 합니다. 위의 hook 연산과 같이 추상화 클래스의 내부를 파악하지 못하면 제대로 사용할 수 없는 기능들이 있기 때문입니다.
또한 추상화 클래스를 작성하는 사람은 오버라이드 해야하는 연산을 너무 많이 넣지 않도록 주의할 필요가 있습니다. 재정의가 필요한 연산이 많아질수록 사용자에게 많은 일을 전가시키게 됩니다.
정리
- 템플릿 메서드 패턴은 변화하는 부분(템플릿)은 추상화 클래스에 변화하지 않는 부분은 서브 클래스에서 구체화 하는 패턴입니다.
- 템플릿 메서드 패턴의 추상화 클래스는 기본 뼈대 부분과 사용자가 무조건 구현해야하는 기본 연산 그리고 필요하다면 hook 연산으로 나뉘게 됩니다.
- 사용자의 경우 템플릿 메서드 패턴을 제대로 사용하기 위해서 추상화 클래스의 내용을 잘 파악하고 있어야합니다.
'IT 관련 기타 > 개발 상식' 카테고리의 다른 글
[개발상식]설정 파일 정리 (0) | 2020.05.19 |
---|---|
JAVA 지역 변수의 범위 최소화 (0) | 2019.10.01 |
자바 SE, EE, ME (0) | 2018.11.22 |
객체지향 프로그래밍 (0) | 2018.05.08 |