[ 전략 패턴 V1 - 예제 ]
- 이번에는 동일한 문제를 전략 패턴(Strategy Pattern)을 사용해서 해결해보자.
- 좋은 설계는 변하는 것(핵심 기능 코드)과 변하지 않는 것(부가 기능 코드)을 분리하는 것이다.
- 템플릿 메서드 패턴은 부모 클래스에 변하지 않는 템플릿을 두고, 변하는 부분을 자식 클래스에 두어서 상속을 사용해서 문제를 해결했다.
- 전략 패턴은 변하지 않는 부분을 Context라는 곳에 두고, 변하는 부분을 Strategy라는 인터페이스를 만들고 해당 인터페이스를 구현하도록 해서 문제를 해결한다. (상속이 아닌 위임)
- 클라이언트가 Context에게 문맥에 맞는 Strategy를 의존성 주입(DI) 해주어야 한다.

- Strategy Interface를 Context Class의 필드로 가진다.
- Context 객체를 생성하면서 Startegy 구현체를 주입 받는다.
Context
/**
* 필드에 전략을 보관하는 방식
*/
@Slf4j
public class ContextV1 {
// Context는 Strategy Interface에만 의존한다. (**다형성**)
// Strategy의 구현체를 변경하거나 새로 만들어도 Context 코드에는 영향을 주지 않는다.
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);
}
}
- Strategy Interface를 Field로 갖고, 템플릿 메서드인 execute를 가진다.
- 템플릿 메서드 중간에 가변 메서드인 strategy.call()을 호출한다.
Strategy
// Strategy Interface (역할)
public interface Strategy {
void call(); // 변하는 것(핵심 기능 코드)을 구현할 메서드
}
// Strategy Class1 (구현)
@Slf4j
public class StrategyLogic1 implements Strategy{
@Override
public void call() {
log.info("비즈니스 로직1 실행");
}
}
// Strategy Class2 (구현)
@Slf4j
public class StrategyLogic2 implements Strategy{
@Override
public void call() {
log.info("비즈니스 로직2 실행");
}
}
Use the strategy pattern
/**
* 전략 패턴 사용
* @throws Exception
*/
@Test
public void strategyV1() throws Exception {
Strategy strategyLogic1 = new StrategyLogic1();
ContextV1 context1 = new ContextV1(strategyLogic1);
context1.execute();
Strategy strategyLogic2 = new StrategyLogic2();
ContextV1 context2 = new ContextV1(strategyLogic2);
context2.execute();
}