record logo record

※참고※
디자인 패턴을 소개할때, 특정한 요구사항을 구현한 코드를 제시하고 해당 코드의 문제점을 분석, 패턴을 적용하는 방식으로 진행합니다.(예제가 적절하지 못할 수 있습니다.)

목차

요구사항

다음과 같은 요구사항을 구현한 Pos 클래스가 있다고 가정하겠습니다.

public class Pos {

    public int calculate(boolean isFirstMember, List<Item> items) {
        int total = 0;
        for (Item item : items) {
            if (isFirstMember) {
                total += (item.getPrice() - 500);
            } else if (!item.isFresh()) {
                total += (item.getPrice() - 300);
            } else {
                total += item.getPrice();
            }
        }
        return total;
    }
}

문제점 분석

위 Pos 클래스는 아래와 같은 문제점을 가지고 있습니다.

public class Pos {

    public int calculate(boolean isFirstMember, List<Item> items) {
        int total = 0;
        for (Item item : items) { // (1) 문제점 발견!
            if (isFirstMember) {
                total += (item.getPrice() - 500);
            } else if (!item.isFresh()) {
                total += (item.getPrice() - 300);
            } else {
                total += item.getPrice();
            }
        }
        return total;
    }
}

앞서 본 문제점을 전략 패턴을 적용하는 것으로 문제를 해결할 수 있습니다.

전략 패턴(Strategy Pattern)

패턴 소개

패턴 적용

앞서 문제를 가진 코드에 전략패턴을 적용하면 다음과 같습니다.

Pos 클래스의 calculate 메소드는 여러 전략들이 섞여있는 것이 아니라 DiscountPolicy 인터페이스 하나만의 의존하는 형태로 변경하였습니다.

이를 통해 새로운 전략이 추가되는 경우, 콘텍스트(Pos)의 코드를 변경할 필요 없이 DiscountPolicy의 콘크리트 클래스를 생성하는 것으로 새로운 전략을 추가할 수 있게 되었습니다.

그리고 한 가지 짚고 넘어가야 하는 부분이 있습니다.

앞서 전략 패턴을 이야기 할때, “콘텍스트의 클라이언트가 콘텍스트에 사용할 전략을 전달해 줍니다.” 라고 이야기 했습니다. 첫 방문 회원에게 할인을 적용하는 시나리오를 예로 들면,

Pos의 클라이언트는 첫 방문 회원 할인이 필요한 경우, 첫 방문 회원 할인 버튼을 호출해서 전략(첫 방문 회원 할인)에 해당하는 콘크리트 클래스를 생성합니다.

이 처럼 콘텍스트의 클라이언트는 구체적인 전략인 콘크리트 클래스와 쌍을 이루고 콘텍스트에 사용할 전략을 전달해 줍니다.

결론

추가로 “마감 직전 손님에게 20% 할인” 한다는 새로운 요구사항 추가된다고 할때, 아래와 같이 새로운 전략이 추가되어도 콘텍스트 코드의 변경없이 새로운 전략을 추가할 수 있음을 볼 수 있습니다.

References