어떤 작업을 처리하는 일부분을 서브 클래스로 캡슐화해 전체 일을 수행하는 구조는 바꾸지 않으면서 특정 단계에서 수행하는 내역을 바꾸는 패턴
전체적으로는 동일하면서 부분적으로 다른 구문으로 구성된 메소드의 코드 중복을 최소화 할 때 유용하다.
구조 예제
// AbstractClass.java
public abstract class AbstractClass {
protected abstract void hook1();
protected abstract void hook2();
public void templateMethod() {
hook1();
hook2();
}
}
// ConcreteClass.java
public class ConcreteClass extends AbstractClass {
@Override
protected void hook1() {
System.out.println("ABSTRACT hook1 implementation");
}
@Override
protected void hook2() {
System.out.println("ABSTRACT hook2 implementation");
}
}
// TemplateMethodPatternClient.java
public class TemplateMethodPatternClient {
public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClass();
abstractClass.templateMethod();
}
}
추상클래스인 AbstractClass에는 실행을 위해 호출 될 public 메소드인 templateMethod가 정의되어 있고 templateMethod 내부에는 hook1 -> hook2 단계를 가지는 추상메소드가 호출된다. 이 추상메소드들은 AbstractClass를 상속받아 구현한 ConcreteClass에서 구체적인 구현이 정의된다.
템플릿 메소드 패턴 예시
예를 들어보자. 피자를 만들 때는 크게 반죽 → 토핑 → 굽기 로 3단계로 이루어져있다.
이 단계는 항상 유지되며, 순서가 바뀔 일은 없다. 물론 실제로는 도우에 따라 반죽이 달라질 수 있겠지만, 일단 모든 피자의 반죽과 굽기는 동일하다고 가정하자. 그러면 피자 종류에 따라 토핑만 바꾸면 된다.
abstract class Pizza {
protected void 반죽() { System.out.println("반죽!"); }
abstract void 토핑() {}
protected void 굽기() { System.out.println("굽기!"); }
final void makePizza() { // 상속 받은 클래스에서 수정 불가
this.반죽();
this.토핑();
this.굽기();
}
}
class PotatoPizza extends Pizza {
@Override
void 토핑() {
System.out.println("고구마 넣기!");
}
}
class TomatoPizza extends Pizza {
@Override
void 토핑() {
System.out.println("토마토 넣기!");
}
}
abstract 키워드를 통해 자식 클래스에서는 선택적으로 메소드를 오버라이드 할 수 있게 된다.
구현방법
1. 대상의 알고리즘을 분석하여 여러 단계로 나눌 수 있는지 확인한다. 어떤 단계들이 모든 자식 클래스에 공통인지 항상 고유한지 고려해야한다.
2. 추상 클래스를 만들고 알고리즘의 단계들을 표현하는 템플릿 메소드와 추상 메소드들의 집합을 선언한다. 해당하는 단계들을 실행하여 템플릿 메소드에서 구조와 윤곽을 잡는다. 템플릿 메소드는 final로 만들어 자식 클래스들이 메소드를 오버라이드 하지 못하도록 한다.
3. 모든 단계가 추상적이어도 되지만 일부 단계에는 디폴트 구현이 있는 것이 도움 될 수 있다.
4. 알고리즘의 각 변형에서 새로운 구상 자식 클래스를 생성한다. 새로운 구상 자식 클래스는 모든 추상 단계들을 반드시 구현해야 하지만 일부 선택 단계는 오버라이드 할 수 있다.
장점
- 중복코드를 줄일 수 있다.
- 자식 클래스의 역할을 줄여 핵심 로직의 관리가 용이하다.
- 객체지향적으로 구성할 수 있다.
단점
- 추상 메소드가 많아지면서 클래스 관리가 복잡해진다.
- 클래스간의 관계와 코드가 꼬여버릴 염려가 있다.
abstract와 Interface의 차이
- abstract :
- 부모의 기능을 자식에서 확장시켜나가고 싶을 때
- Interface
- 해당 클래스가 가진 함수의 기능을 활용하고 싶을 때
출처:
https://gyoogle.dev/blog/design-pattern/Template%20Method%20Pattern.html
'CS(Computer Science) > Design Pattern' 카테고리의 다른 글
옵저버 패턴 (4) | 2023.01.12 |
---|---|
팩토리 메소드 패턴 (0) | 2023.01.09 |
싱글톤 패턴 (0) | 2023.01.08 |
어댑터 패턴 (0) | 2023.01.08 |