[Design Pattern] 템플릿 메서드 패턴
0. 들어가기 전에
이 글은 예제 코드를 이용하여 템플릿 메서드 패턴을 적용시켜보고, 어떠한 장단점이 있는지 설명하는 글입니다.
1. 템플릿 메서드 패턴 적용 전
현재 주문 로직과 결제 로직이 있다.(간단하게 로그로 표현했다.)
@Slf4j
public class DefaultOrderLogic {
private void order() {
log.info("주문 로직 실행");
}
}
@Slf4j
public class DefaultPayLogic {
private void pay() {
log.info("결제 로직 실행");
}
}
그런데 여기에 요구사항으로 메서드의 시작과 끝에 로그를 출력하는 기능을 추가한다고 하자.
그렇다면 위의 코드는 아래처럼 바뀌게 된다.
@Slf4j
public class DefaultOrderLogic {
private void order() {
log.info("메서드 시작");
log.info("주문 로직 실행");
log.info("메서드 끝");
}
}
@Slf4j
public class DefaultPayLogic {
private void pay() {
log.info("메서드 시작");
log.info("결제 로직 실행");
log.info("메서드 끝");
}
}
여기까지는 할 만하다. 그렇다면 여기에 주문 취소 로직이 추가되면 어떨까?
@Slf4j
public class DefaultCancelLogic {
private void cancel() {
log.info("메서드 시작");
log.info("주문 취소 로직 실행");
log.info("메서드 끝");
}
}
그리고 모든 메서드의 실행 시간을 재는 로직이 추가되어야 한다면??
함수가 많으면 많을수록 코드를 유지보수하는 비용이 커지게된다.
이때 발생하는 문제들을 템플릿 메서드 패턴으로 해결할 수 있다.
2. 템플릿 메서드 패턴이란?
상속을 활용하여 변하는 부분과 변하지 않는 부분을 분리하는 디자인 패턴 중의 하나이다.
정의 자체는 좋아보인다. 어떻게 적용할 수 있을까?
3. 적용 후 코드
첫 단계로 공통된 로직들을 추상화 해야한다.
@Slf4j
public abstract class AbstractTemplate {
public void commonLogic() {
log.info("메서드 시작");
specificLogic();
log.info("메서드 끝");
}
protected abstract void specificLogic();
}
공통된 로직은 commonLogic()
에 넣고, 바뀌는 부분은 AbstractTemplate을 상속받아 specificLogic을 Override 해주면 된다.
그러면 적용 후 코드는 아래와 같은 모양이 된다.
@Slf4j
public class OrderTemplateMethod extends AbstractTemplate {
@Override
protected void specificLogic() {
log.info("주문 로직 실행");
}
}
@Slf4j
public class PayTemplateMethod extends AbstractTemplate {
@Override
protected void specificLogic() {
log.info("결제 로직 실행");
}
}
@Slf4j
public class CancelTemplateMethod extends AbstractTemplate {
@Override
protected void specificLogic() {
log.info("주문 취소 로직 실행");
}
}
이제 공통된 요구사항이 변경되었을 때 AbstractTemplate
을 수정하면 상속 받은 모든 클래스에 적용이 될 것이다.
또한, 메인 로직은 공통 로직에 영향을 주지 않고, 쉽게 교체 할 수 있다.
4. 장단점
- 장점
- 공통 로직이 변경되었을 경우 하나의 추상 클래스만 수정하면, 수정된 내용들을 나머지 클래스에서도 반영할 수 있다.
- 클래스 각각의 로직을 변경해도 공통 로직에 영향을 주지 않는다.
- 단점
- 상속을 사용했기 때문에 상속의 단점을 모두 가지고 있다.
- 기능을 일부만 사용하지만, 부모 클래스의 모든 구현을 알고 있다. -> 캡슐화 위반
- 컴파일 시점에 관계가 결정되어 결합도가 높아진다.
- 하나를 수정하려면 불필요하게 다른 클래스들을 추가하거나 수정해야한다. -> 설계 유연 X, 클래스의 폭발
- 상속을 사용했기 때문에 상속의 단점을 모두 가지고 있다.
※ 출처
'DESIGN_PATTERN' 카테고리의 다른 글
[Design Pattern] 전략 패턴 (2) | 2023.02.22 |
---|