Search
Duplicate
📒

[Java Study] xy. 전략 패턴

상태
완료
수업
Java Study
주제
Design Pattern
연관 노트
3 more properties
참고

전략 패턴

NOTE
하나의 메시지와 책임을 정의하고, 이를 수행할 수 있는 다양한 전략을 만든 후, 다형성을 통해 전략을 선택해 구현을 실행하는 패턴.
필요 개념: 컴포지션
활용도: 부담없이 사용해볼만 함
난이도: 간단
패턴이 필요한 상황: 상속 상황에서 내부 코드의 빈번한 중복
[ 참고]
템플릿 메서드와 차이점
템플릿 패턴
런타임에 타입선택
추상 메서드로 의존성 역전
최악의 경우 조합폭발(class가 무수히 많아짐)
전략 패턴
런타임에 합성(조립)
추가 인터페이스로 의존성 분산
의존성 폭발 발생이 생길 수 있음

전략 패턴 V1

NOTE
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 인터페이스

public interface Strategy { void call(); }
Java
복사
@Slf4j public class StrategyLogic1 implements Strategy { @Override public void call() { log.info("비즈니스 로직1 실행"); } }
Java
복사
@Slf4j public class StrategyLogic2 implements Strategy { @Override public void call() { log.info("비즈니스 로직2 실행"); } }
Java
복사

execute 호출

// 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
복사
// 익명클래스 사용 @Test void strategyV2(){ Strategy strategyLogic1 = new Strategy() { @Override public void call() { log.info("비즈니스 로직1 실행"); } }; ContextV1 contextV1 = new ContextV1(strategyLogic1); log.info("strategyLogic1={}", strategyLogic1.getClass()); contextV1.execute(); Strategy strategyLogic2 = new Strategy() { @Override public void call() { log.info("비즈니스 로직2 실행"); } }; ContextV1 contextV2 = new ContextV1(strategyLogic2); log.info("strategyLogic2={}", strategyLogic2.getClass()); contextV2.execute(); }
Java
복사
// 익명 클래스 사용 인스턴스 생성하여 파라미터 전달 @Test void strategyV3(){ ContextV1 contextV1 = new ContextV1(new Strategy() { @Override public void call() { log.info("비즈니스 로직1 실행"); } }); contextV1.execute(); ContextV1 contextV2 = new ContextV1(new Strategy() { @Override public void call() { log.info("비즈니스 로직2 실행"); } }); contextV2.execute(); }
Java
복사
// 람다식 사용 @Test void strategyV4(){; ContextV1 contextV1 = new ContextV1(() -> log.info("비즈니스 로직1 실행")); contextV1.execute(); ContextV1 contextV2 = new ContextV1(() -> log.info("비즈니스 로직2 실행")); contextV2.execute(); }
Java
복사
하나의 메서드를 갖는 인터페이스는 람다식을 통해 익명 클래스 인스턴스를 생성할 수 있다.

전략 패턴 V2

NOTE
Strategy 인터페이스를 Context 클래스의 필드로 갖지않고, execute 호출마다 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
복사

Strategy 인터페이스

public interface Strategy { void call(); }
Java
복사
@Slf4j public class StrategyLogic1 implements Strategy { @Override public void call() { log.info("비즈니스 로직1 실행"); } }
Java
복사
@Slf4j public class StrategyLogic2 implements Strategy { @Override public void call() { log.info("비즈니스 로직2 실행"); } }
Java
복사

execute 호출

// Strategy 구현 클래스 생성 @Test void strategyV1(){ ContextV2 context = new ContextV2(); context.execute(new StrategyLogic1()); context.execute(new StrategyLogic2()); }
Java
복사
// 익명클래스 사용 @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 실행"); } }); }
Java
복사
// 람다식 사용 @Test void strategyV3(){ ContextV2 context = new ContextV2(); context.execute(() -> log.info("비즈니스 로직1 실행")); context.execute(() -> log.info("비즈니스 로직2 실행")); }
Java
복사
하나의 메서드를 갖는 인터페이스는 람다식을 통해 익명 클래스 인스턴스를 생성할 수 있다.

전략 패턴 V1 vs V2

NOTE

V1 (필드 방식)

Strategy 구현체Context에 주입받아서, execute를 호출만 하면되므로 간편하다
하지만 다른 전략을 사용하려면, 다른 Strategy 구현체를 주입받은 새로운 Context객체를 생성해야 한다.

V2(파라미터 방식)

Strategy 구현체execute메서드 파라미터로 받는다.
execute호출마다 파라미터를 넘겨야하지만, execute호출마다 유연하게 전략을 변경할 수 있다.