전략패턴
전략 패턴은 실행 중에 알고리즘 전략을 선택하여 객체 동작을 실시간으로 바뀌도록 할 수 있게 하는 행위 디자인 패턴입니다. 어떤 일을 수행하는 알고리즘이 여러 가지 일 때, 동작들을 미리 전략으로 정의함으로써 손쉽게 전략을 교체할 수 있는, 알고리즘 변형이 빈번하게 필요한 경우에 적합합니다..
전략 패턴 구조
코드로 바로 어떤 구조인지 확인하러 가시죠
public interface Strategy {
void call();
}
---------------------------------------------------
@Slf4j
public class StrategyLogicV1 implements Strategy{
@Override
public void call() {
log.info("비즈니스 로직1 실행");
}
}
---------------------------------------------------
@Slf4j
public class StrategyLogicV2 implements Strategy{
@Override
public void call() {
log.info("비즈니스 로직2 실행");
}
}
Strategy 인터페이스는 변하는 알고리즘을 의미합니다. StrategyLogic1과 StrategyLogic2는 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);
}
}
전략을 필드로 가지지 않습니다. 대신에 전략을 execute(..) 가 호출될 때마다 항상 파라미터로 전달받습니다.
테스트 클래스를 작성하여 어떤 결과를 보여주는지 확인했습니다.
@Slf4j
public class ContextV2Test {
/**
* 전략 패턴 적용
*/
@Test
void strategyV1() {
ContextV2 context = new ContextV2();
context.execute(new StrategyLogicV1());
context.execute(new StrategyLogicV2());
}
전략 패턴 파라미터 실행을 그림으로 표현하면
1. 클라이언트가 Context를 실행하면서 Strategy를 인수로 전달합니다.
2. excute 로직을 실행합니다.
3. strategy.call로직을 수행합니다.
4. excute로직이 종료됩니다.
하지만 단지 전략패턴만 적용하였을 때 StrategyLogicV1과 StrategyLogicV2가 코드상에 나타나 있습니다. 이를 익명 내부 클래스로 전환할 수 있습니다.
/**
* 전략 패턴 익명 내부 클래스
*/
@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 실행");
}
});
}
Strategy 인터페이스에 메서드가 하나만 있어서 이를 람다로도 바꿀 수 있다. 인텔리제이를 사용하면 정말 변환이 쉽게 변경 가능합니다.
/**
* 전략 패턴 익명 내부 클래스2, 람다
*/
@Test
void strategyV3() {
ContextV2 context = new ContextV2();
context.execute(() -> log.info("비즈니스 로직1 실행"));
context.execute(() -> log.info("비즈니스 로직2 실행"));
}
확실히 간략해진 코드를 확인할 수 있습니다. 하지만 람다를 사용하여 구현을 할 경우 interface에 메서드가 하나만 있어야 하는 주의 사항이 있습니다!!
전략패턴을 좀 더 이해할 수 있었던 시간이었던 같습니다. 감사합니다!!
김영한 님의 스프링 핵심 원리 - 고급편을 기반으로 작성한 포스팅입니다. 문제 발생 시 삭제하겠습니다!
'백엔드 지식 저장소' 카테고리의 다른 글
Spring Data MongoDB에 QueryDSL 적용하기 (0) | 2024.02.20 |
---|---|
Git 자주 사용하는 명령어 정리 (0) | 2024.02.02 |
java: Attempt to recreate a file for type study.querydsl.entity.Qclass 문제 해결 (0) | 2024.01.11 |
트랜잭션 AOP 주의사항!! (1) | 2024.01.05 |
요청 값으로 Entity를 직접 받았던 나를 반성하며.... (0) | 2023.12.26 |