티스토리 뷰
템플릿 메서드 패턴
설명
- 코드에 변하는 부분과 변하지 않는 부분이 있을 때, 변하지 않는 부분을 추상 클래스 내 메서드로 정의하고, 변하는 부분을 추상 클래스 내 abstract 메서드로 정의하여 자식 클래스에서 변하는 부분을 abstract 메서드를 override 하여 구현하는 패턴.
코드 예시
public abstract class AbstractTemplate {
public void execute() {
long startTime = System.currentTimeMillis();
//비즈니스 로직 실행
call();
//비즈니스 로직 종료
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("resultTime={}", resultTime);
}
protected abstract void call();
}
public class SubClassLogic1 extends AbstractTemplate{
@Override
protected void call() {
log.info("비즈니스 로직1 실행");
}
}
public class SubClassLogic2 extends AbstractTemplate{
@Override
protected void call() {
log.info("비즈니스 로직2 실행");
}
}
단점
- 상속을 사용한다.
- 자식 클래스는 부모 클래스(abstract class) 의 기능을 전혀 사용하지 않지만 부모 클래스의 코드를 가지고 있다.
- 별도의 자식 클래스 혹은 익명내부클래스를 정의해야 한다. -> 번거롭다.
전략 패턴
설명
- 변하지 않는 부분을
context
에 정의하고, 변하는 부분을Strategy
라는 인터페이스를 정의 && 이 인터페이스를 구현하는 방식으로 작성한다. context
내 필드 값으로Strategy
인터페이스를 가지고 있고, 이곳에 구체Strategy
클래스를 전달해 변하는 부분을 처리한다.- -> 스프링이 DI 시 사용하는 방식!
코드 예시
public class ContextV1 {
private Strategy strategy;
public ContextV1(Strategy strategy) {
this.strategy = strategy;
}
public void execute() {
long startTime = System.currentTimeMillis();
//비즈니스 로직 실행
strategy.call(); //위임
//비즈니스 로직 종료
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("resultTime={}", resultTime);
}
}
public interface Strategy {
void call();
}
public class StrategyLogic1 implements Strategy{
/*
전략패턴 장점 : 템플릿-메소드 패턴과 달리 Interface 만을 구현 -> 부모 클래스 코드를 가지고 있지 않다. -> 부모 클래스 변경으로부터 자유로움.
이펙티브 자바, 상속보다 위임!
*/
@Override
public void call() {
log.info("비즈니스 로직1 실행");
}
}
public class StrategyLogic2 implements Strategy{
@Override
public void call() {
log.info("비즈니스 로직2 실행");
}
}
public class ContextV1Test {
@Test
void templateMethodV0() {
logic1();
logic2();
}
private void logic1() {
long startTime = System.currentTimeMillis();
//비즈니스 로직 실행
log.info("비즈니스 로직1 실행");
//비즈니스 로직 종료
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("resultTime={}", resultTime);
}
private void logic2() {
long startTime = System.currentTimeMillis();
//비즈니스 로직 실행
log.info("비즈니스 로직2 실행");
//비즈니스 로직 종료
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("resultTime={}", resultTime);
}
@Test
void strategyV1() {
StrategyLogic1 strategyLogic1 = new StrategyLogic1();
ContextV1 context1 = new ContextV1(strategyLogic1);
context1.execute();
StrategyLogic2 strategyLogic2 = new StrategyLogic2();
ContextV1 context2 = new ContextV1(strategyLogic2);
context2.execute();
}
@Test
void strategyV2() {
Strategy strategyLogic1 = new Strategy() {
@Override
public void call() {
log.info("비즈니스 로직1 실행");
}
};
ContextV1 context1 = new ContextV1(strategyLogic1);
log.info("strategyLogic1={}", strategyLogic1.getClass());
context1.execute();
Strategy strategyLogic2 = new Strategy() {
@Override
public void call() {
log.info("비즈니스 로직1 실행");
}
};
ContextV1 context2 = new ContextV1(strategyLogic1);
log.info("strategyLogic2={}", strategyLogic2.getClass());
context2.execute();
}
@Test
void strategyV3() {
ContextV1 context1 = new ContextV1(new Strategy() {
@Override
public void call() {
log.info("비즈니스 로직1 실행");
}
});
context1.execute();
ContextV1 context2 = new ContextV1(new Strategy() {
@Override
public void call() {
log.info("비즈니스 로직1 실행");
}
});
context2.execute();
}
@Test
void strategyV4() {
ContextV1 context1 = new ContextV1(() -> log.info("비즈니스 로직1 실행"));
context1.execute();
ContextV1 context2 = new ContextV1(() -> log.info("비즈니스 로직2 실행"));
context2.execute();
}
}
단점
context
와strategy
를 조립한 이후에는 전략을 변경하기가 번거롭다.
템플릿 콜백 패턴
설명
- 전략 패턴과 다르게,
Strategy
를 필드에 가지고 있지 않고, 메서드 파라미터로 넘겨받는 방식. Context
를 실행할 때마다Strategy
를 변경할 수 있다. 즉, 일반적인 전략패턴보다 유연하게 전략 변경이 가능하다.- 변하지 않는 부분 : 템플릿
- 변하는 부분(전략) : 콜백 -> ‘실행 가능한 코드 조각’ 을 의미.
코드 예시
public class TimeLogTemplate {
public void execute(Callback callback) {
long startTime = System.currentTimeMillis();
//비즈니스 로직 실행
callback.call(); //위임
//비즈니스 로직 종료
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("resultTime={}", resultTime);
}
}
public interface Callback {
void call();
}
public class TemplateCallbackTest {
/**
* 템플릿 콜백 패턴 - 익명 내부 클래스
*/
@Test
void callbackV1() {
TimeLogTemplate template = new TimeLogTemplate();
template.execute(new Callback() {
@Override
public void call() {
log.info("비즈니스 로직1 실행");
}
});
template.execute(new Callback() {
@Override
public void call() {
log.info("비즈니스 로직2 실행");
}
});
}
/**
* 템플릿 콜백 패턴 - 익명 내부 클래스, 람다
*/
@Test
void callbackV2() {
TimeLogTemplate template = new TimeLogTemplate();
template.execute(() -> log.info("비즈니스 로직1 실행"));
template.execute(() -> log.info("비즈니스 로직2 실행"));
}
}
출처
'OOP' 카테고리의 다른 글
프록시 패턴 vs 데코레이터 패턴 (0) | 2022.09.18 |
---|---|
예시로 이해하는 데코레이터(Decorator) 패턴 (0) | 2021.06.28 |
예시로 이해하는 상태(State) 패턴 (0) | 2021.06.28 |
예시로 이해하는 템플릿 메소드(Template Method) 패턴 (0) | 2021.06.27 |
예시로 이해하는 전략(Strategy) 패턴 (0) | 2021.06.27 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 백기선
- provider
- 프록시
- 서비스추상화
- 카카오
- 프록시패턴
- OOP
- 객체지향
- 데코레이터패턴
- SOLID
- ec2
- 토비의스프링
- 예외처리
- c++
- BOJ
- 디자인패턴
- 프로그래머스
- 메서드레퍼런스
- AOP
- 자바
- 김영한
- 토비
- 코딩테스트
- 템플릿콜백
- 코테
- 스프링
- gracefulshutdown
- java
- 토비의봄TV
- 자바스터디
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함