2022. 10. 29. 12:45ㆍ토비의 스터디
1. 전략 패턴이란
2. 전략 패턴을 사용하는 이유
3. 전략 패턴 예제
4. 적용 사례(Comparator)
순서로 전략패턴을 빠르게 알아보자!
1. 전략 패턴이란
- 실행 중에 알고리즘을 선택할 수 있게 하는 디자인 패턴
- 특정 컨텍스트에서 알고리즘을 별도로 분리하는 설계 방법
예시상황
한 과일 매장은 상황에 따라 다른 가격 할인 정책을 적용하고 있습니다.
제일 먼저 온 손님에게 10%를 할인해주고 마지막 손님은 20%,
그리고 신선도가 떨어진 과일에 대해서는 20% 할인을 해주고 있습니다.
이 상황에서 쉽게 생각할 수 있는 코드는 if-else 구문이다.
public double calculate(boolean isFirstGuest, boolean isLastGuest, List<Item> items) {
int cost = 0;
for (Item item : items) {
if (isFirstGuest) {
cost += item.getPrice() * 0.9;
} else if (isLastGuest) {
cost += item.getPrice() * 0.8;
} else if (!item.isFresh()) {
cost += item.getPrice() * 0.8;
} else {
cost += item.getPrice();
}
}
return cost;
}
그런데 이 예시 상황처럼 할인 전략이 여러개로 나뉘는 경우 전략 패턴을 적용해볼 수 있다.
정의를 다시 살펴보면
전략 패턴이란
=> 특정 컨텍스트에 다양한 알고리즘을 별도로 분리해 관리하는 패턴
즉, 위의 상황에서는 ’가격 계산’이라는 컨텍스트에서 적용되는 다양한 할인 알고리즘(전략)을 별도로 관리하는 것
따라서 전략 패턴을 적용하기 위해
할인이라는 전략(알고리즘)을 DiscountPolicy라는 인터페이스를 통해 분리하여 관리할 것이다.
인터페이스를 사용하는 이유는, 다형성을 적용하기 위해서다.
전략을 사용하는 쪽에서는, 어떤 전략이 주입되는지 상관하지 않고 DiscountPolicy의 메소드만 사용하면 된다.
할인 정책이 3가지인데,
DiscountPolicy 인터페이스 아래에
1) 첫번째 손님의 경우 10% 할인 -> FirstCustomerDiscount 클래스 생성 후 구현
2) 마지막 손님의 경우 20% 할인 -> LastCustomerDiscount 클래스 생성 후 구현
3) 신선하지 않은 야채의 경우 20% 할인 -> NotFreshVegetable 클래스 생성 후 구현
이렇게 세가지 클래스를 구현하면 되겠다.
구체적인 할인 전략은 각각의 구현 클래스에서 정의하면 된다.
그럼 이제 DiscountPolicy를 사용하는 쪽에서는 외부로부터 DiscountPolicy 타입의 전략을 주입받으면 된다.
빨간 네모 부분이 사용하는 쪽에서 구체적인 전략을 주입해주는 모습이다.
만약 new FirstCustomerDiscount() 대신에 new LastCustomerDiscount() 을 주입해준다면
20% 할인된 계산 금액이 출력될 것이다.
전략 패턴이란 특정 컨텍스트에 다양한 알고리즘을 별도로 분리해 관리하는 패턴이라고 하였는데
이제 어느정도 감을 잡았을 것이라고 생각한다.
2. 전략 패턴을 사용하는 이유
새로운 할인 정책이 추가되는 경우
이전 상황에서 전략패턴을 사용하기 전 코드인 if-else문을 다시 보자.
만약 새로운 할인 정책이 등장한다면
else-if 문을 하나 더 추가해야 할 것이다.
지금은 단순한 코드지만 훨씬 복잡한 코드라면 실수를 유발하기 좋다.
하지만 전략패턴을 사용한다면 단순히 DiscountPolicy를 구현한 전략을 하나 더 생성하기만 하면 된다.
새로운 전략에 대해서는 새로운 클래스를 통해 관리하기 때문에 컨텍스트 코드의 수정을 하나도 할 필요가 없다.
즉 OCP 원칙을 준수할 수 있는 것이다.
3. 전략 패턴 예제
앞서 할인 유형을 전략 패턴으로 구사하는 예제를 살펴보았다.
이번에는 또 다른 상황을 살펴보자.
=> 이 상황에서도 마찬가지로 전략 패턴을 적용하기 위해
‘결제’라는 컨텍스트를 PaymentStrategy 인터페이스로 분리한 뒤
신용카드, 카카오페이 전략(알고리즘)을 구현한다.
결제 방법에 따라 콘솔에 출력되게끔 구현하였다.
아래 ShoppingCart 클래스의 pay 메소드를 실행할 때, 구체적인 전략 타입을 파라미터로 전달해주기만 하면 된다.
파라미터 타입이 PaymentStrategy 인터페이스로 다형성의 장점을 한껏 살리는 것이다.
그럼 이제 pay 메소드를 호출할 때 구체적인 전략을 정해서 넣어주기만 하면 자동으로 실행된다.
결과는 아래와 같다.
4. 적용 사례(Comparator)
Arrays, Collections 클래스의 sort() 메소드는 다들 한 번씩 사용해 보셨을 것이다.
이 sort 메소드를 사용할 때 정렬기준을 넣어주어야 하는데 Comparator 인터페이스가 정렬 기준 역할을 수행한다.
sort 메소드는 다음과 같이 동작한다.
1. 미리 전략을 구성하고 Comparator 인터페이스안에 전략을 넣어 감싸준다.
=> 대표적인 전략으로는 내림차순, 오름차순이 있겠다. 아래 빨간색 네모가 개별 전략인 셈이다.
2. 실제 대상 함수인 sort에 컬렉션과 함께
전략(알고리즘)이 포함된 Comparator 객체를 넘겨준다.
3. 실제 sort함수가 불릴 때 comparator
전략에 따라 정렬을 수행한다.
comparator에 담긴 전략에 따라 sort() 결과가 다르게 수행된다.
따라서 Comparator를 전략 패턴의 대표사례라고 할 수 있겠다.
참고한 링크
'토비의 스터디' 카테고리의 다른 글
[토비의 스프링 3.1] 3.3 JDBC 전략 패턴의 최적화 (0) | 2022.07.07 |
---|---|
[토비의 스프링 3.1] 3.2 변하는 것과 변하지 않는 것 (0) | 2022.07.06 |
[토비의 스프링 3.1] 3.1 다시 보는 초난감 DAO (0) | 2022.07.05 |
[토비의 스프링 3.1] 2.5 학습 테스트로 배우는 스프링 (0) | 2022.07.04 |
[토비의 스프링 3.1] 2.4 스프링 테스트 적용 (0) | 2022.06.30 |