public class Calculator {
public int calculate(boolean firstGuest, List<Item> items) {
int sum = 0;
for (Item item : items) {
if (firstGuest) {
sum += (int )(item.getPrice() * 0.9); // 첫 손님 10% 할인
else if (! item.isFresh())
sum += (int )(item.getPrice() * 0.8); // 덜 신선한 과일 20% 할인
}
return sum;
}
문제점
전략패턴?
특정 콘텍스트에서 전략을 별도로 분리하는 설계 방법
- 전략 : 구현 로직(할인 방법)을 추상화
- DiscountStrategy 인터페이스는 상품의 할인 금액 계산을 추상화했다.
- 콘텍스트 : 가격 계산 자체를 책임지는 Calculator
- 각 콘크리트(연산에 대한 구현) 클래스는 상황에 맞는 할인 계산 로직을 제공한다.
전략 패턴에서 콘텍스트는 사용할 전략을 직접 선택하지 않는 대신,
클라이언트가 콘텍스트에 사용할 전략을 전달해준다. (의존성 주입 이용)
그리고 전략이 어떤 메서드를 제공할 지의 여부는 콘텍스트가 전략을 어떤 식으로 사용하느냐에 따라 달라진다.
public class Calculator {
private DiscountStrategy discountStrategy;
public Calculator(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
public int calculate(List<Item> items) {
int sum = 0;
for (Item item : items) {
sum += discountStrategy.getDiscountPrice(item);
}
return sum;
}
public interface DiscountStrategy {
int getDiscountPrice(Item item);
}
만약 각 아이템 별로 할인 정책이 있고 전체 금액에 대한 할인 정책이 별도로 필요하다면?
public interface DiscountStrategy {
int getDiscountPrice(Item item);
int getDiscountPrice(int totalPrice);
}
또는, 전체 금액 할인 정책을 위한 전략을 별도 인터페이스로 분리할 수도 있다.
public interface DiscountStrategy {
int getDiscountPrice(Item item);
}
public interface TotalPriceDiscountStrategy {
int getDiscountPrice(int totalPrice);
}
전략 객체는 콘텍스트를 사용하는 클라이언트에서 직접 생성한다.
첫 번째 손님에 대해 할인을 해주는 구현체가 있다고 가정해보자.
public class FirstGuestDiscountStrategy implements DiscountStrategy {
@Override
public int getDisconutPrice(Item item) {
return (int) (item.getPrice() * 0.9);
}
}
private DiscountStrategy discountStrategy;
public void onFirstGuestButtonClick() {
// 첫 손님 할인 버튼 누를 때 생성
strategy = new FirstGuestDiscountStrategy();
}
public void onCalculationButtonClick() {
// 계산 버튼 누를 때 실행
Calculator calculator = new Calulator(strategy);
int price = calculator.calculate(items);
}
전략 패턴을 적용할 때 얻을 수 있는 이점은 콘텍스트 코드의 변경없이 새로운 전략을 추가할 수 있다는 점이라고 한다.
마지막 손님 대폭 할인 정책을 추가한다고 가정해보자.
private DiscountStrategy discountStrategy;
public void onFirstGuestButtonClick() {
// 마지막 손님 대폭 할인 버튼 누를 때 생성
strategy = new LastGuestDiscountStrategy();
}
public void onCalculationButtonClick() {
// 계산 버튼 누를 때 실행
Calculator calculator = new Calulator(strategy);
int price = calculator.calculate(items);
}
전략 패턴은 언제 사용할까?
- 일반적으로 if문으로 구성된 코드 블록이 비슷한 기능을 수행하는 경우 전략 패턴을 적용함으로써 코드를 확장 가능하도록 변경할 수 있다고 한다.
- 완전히 동일한 기능을 제공하지만 성능의 장단점에 따라 알고리즘을 선택해야 하는 경우에도 전략 패턴을 사용한다고 한다.