Search
〰️

Strategy Pattern

Strategy Pattern

정의

알고리즘 제품군을 정의하고 각각을 캡슐화하여 상호 교환 가능하게 만들자. 전략을 사용하면 알고리즘을 사용하는 클라이언트와 독립적으로 알고리즘을 변경할 수 있다.
변하지 않는 알고리즘을 Context Inteface로 만든다.
변하는 알고리즘을 Strategy Interface로 만든다
Context는 Strategy Interface에 의존
Strategy의 구현체를 변경하거나 새로 만들어도 Context 코드에는 영향을 주지 않는다.

예제

Context
@Slf4j 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); } }
Java
복사
Strategy (Interface)
public interface Strategy { void call(); }
Java
복사
StrategyLogic (구현체)
@Slf4j public class StrategyLogic1 implements Strategy { @Override public void call() { log.info("비즈니스 로직1 실행"); } }
Java
복사
사용
원하는 Strategy 구현체를 사용
/** * 전략 패턴 사용 */ @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(); }
Java
복사
→ Context는 단순히 Strategy Interface에만 의존! 구현체가 변경되어도 영향이 없음

선 조립, 후 실행

Context의 내부 필드에 Strategy를 두고 사용하는 부분이 핵심!
Context와 Strategy를 실행전에 원하는 모양으로 조립해두고, 그 다음에 Context를 실행하는 선 조립, 후 실행 방식에서 매우 유용하다!
스프링으로 애플리케이션 개발할 경우와 비슷 (의존관계 주입)

단점

Context와 Strategy를 조립한 이후에는 전략을 변경하기가 번거롭다.
실행시마다 원하는 전략을 유연하게 변경
Context
/** * 전략을 파라미터로 전달받는 방식 */ @Slf4j public class ContextV2 { public void execute(Strategy strategy) { long startTime = System.currentTimeMillis(); // 비즈니스 로직 실행 strategy.call(); // 위임 // 비즈니스 로직 종료 long endTime = System.currentTimeMillis(); long resultTime = endTime - startTime; log.info("resultTime={}", resultTime); } }
Java
복사
실행
@Slf4j public class ContextV2Test { /** * 전략 패턴 적용 --> 파라미터로 전달 * * 그때그때 전략을 인수로 전달한당 (유연한 변경) */ @Test void strategyV1() { ContextV2 context = new ContextV2(); context.execute(new StrategyLogic1()); //구현체1 context.execute(new StrategyLogic2()); //구현체2 } /** * 전략패턴 익명 내부 클래스 */ @Test void strategyV2() { ContextV2 context = new ContextV2(); context.execute(new Strategy() { @Override public void call() { log.info("비즈니스 로직1 실행"); } }); context.execute(new Strategy() { @Override public void call() { log.info("비즈니스 로직2 실행"); } }); } /** * 전략패턴 익명 내부 클래스 --> 람다 */ @Test void strategyV3() { ContextV2 context = new ContextV2(); context.execute(() -> log.info("비즈니스 로직1 실행")); context.execute(() -> log.info("비즈니스 로직2 실행")); } }
Java
복사

Spring에서의 Strategy Pattern - Template Callback

Context → Template
Strategy → Callback
Spring에서 JdbcTemplate, RestTemplate 등 xxxTemplate의 이름을 가진 코드

예제

Template
public class TraceTemplate { private final LogTrace trace; public TraceTemplate(LogTrace trace) { this.trace = trace; } public <T> T execute(String message, TraceCallback<T> callback) { TraceStatus status = null; try { status = trace.begin(message); // 비즈니스 로직 호출 T result = callback.call(); trace.end(status); return result; } catch (Exception e) { trace.exception(status, e); throw e; } } }
Java
복사
Callback
public interface TraceCallback<T> { T call(); }
Java
복사