[Design Pattern] Strategy Pattern

Strategy Pattern

특정 콘텍스트에서 알고리즘(전략)을 별도로 분리하는 설계 방법

예시 상황

과일 매장에서 상황에 따라 다른 가격 할인 정책을 적용한다.

가격 계산 모듈에 할인 정책 구현

public class Calculator {

    public int calculator(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% 할인
            } else {
                sum += item.getPrice();
            }
        }

        return sum;
    }
}

예시의 문제점

전략 패턴을 적용한 Calculator의 구현

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;
    }
}

Calculator에서 사용하는 전략 인터페이스

public interface DiscountStrategy {
    
    int getDiscountPrice(Item item);
}

DiscountStrategy 인터페이스를 구현한 콘크리트 클래스

public class FirstGuestDiscountStrategy implements DiscountStrategy {

    @Override
    public int getDiscountPrice(Item item) {
        return (int) (item.getPrice() * 0.9);
    }
}

Calculator의 클리어언트 Calculator를 사용하는 코드에서 콘크리트 클래스를 생성한다.

public class Client {
    
    private DiscountStrategy discountStrategy;

    public void onFirstGuestButtonClick() {
        discountStrategy = new FirstGuestDiscountStrategy();
    }
    
    public void onLastGuestButtonClick() {
        discountStrategy = new LastGuestDiscountStrategy();
    }

    public void onCalculationButtonClick() {
        Calculator calculator = new Calculator(discountStrategy);
        int price = calculator.calculate(items);
    }
}

Reference