본문으로 바로가기
728x90
반응형
SMALL

본 교재를 기반으로 정리합니다

 

전략패턴(Strategy)

매장에는 '첫 손님 할인' , '덜 신선한 과일 할인' 정책이 있다.

if-else 블록이 포함된 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Calculator{
 
    public int calculate(boolean firstGuest, List<Item> items){
        int sum = 0;
        for (Item item : items){
            //첫 손님 10% 할인
            if(firstGuest){
                sum += (int) (item.getPrice() * 0.9); 
            }
            //덜 신선한 과일 20% 할인
            else if(! item.isFresh()){
                sum += (int) (item.getPrice() * 0.8);     
            }
            else{
                sum += item.getPrice();
            }
            return sum;
        }
    }
}
cs

문제점

할인 정책이 추가될 수록 if 블록문을 늘려줘야 한다

때문에 코드 분석이 어려움에 빠질 수 있다.

해결

DiscountStrategy 인터페이스(전략)

할인 금액 계산을 추상화

전략 콘크리트 클래스

할인 계산 알고리즘 제공

Calculator 클래스(콘텍스트)

가격 합산 계산의 책임

 

전략 패턴에서 콘텍스트는 사용할 전략을 직접 선택하지 않는다.

DI를 통해서 컨텍스트에 전략을 전달해준다.

전략 패턴 적용 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
    }
}
cs

 

Calculator 클래스는 생성자를 통해 사용할 전략 객체를 전달 받고, calculate() 메서드에서 각 Item의 가격을 계산할 때 전략 객체를 사용하고 있다.

DiscountStrategy 인터페이스

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

 

만약에 할인 정책에 대해서 전체 가격에 대한 할인 정책이 추가로 필요하다면?

인터페이스에 메서드를 추가하자

1
2
3
4
5
6
7
public interface DiscountStrategy{
 
    int getDiscountPrice(Item item);
   
    int getDiscountPrice(int totalPrice);
    
}
cs
 

또는

별도 인터페이스를 분리할 수도 있다.

1
2
3
4
5
6
7
public interface ItemDiscountStrategy{
    int getDiscountPrice(Item item);
 }
 
 public interface TotalPriceDiscountStrategy{
       int getDiscountPrice(int totalPrice);
 }
cs

 

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

1
2
3
4
5
6
7
public class FirstGuestDiscountStrategy implements DiscountStrategy {
 
    @Override
    public int getDiscountPrice(Item item){
        return (int) (item.getPrice() * 0.9);
    }
}
cs

 

첫번째 손님이 들어와서 계산하면

1. 계산기에선 첫번째 손님 할인 적용버튼을 누른뒤,  2. 계산 버튼을 누른다.

이를 처리하는 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
private DiscountStrategy strategy;
 
//첫 손님 할인 버튼
public void onFirstGuestButtonClick(){
    strategy = new FirstGuestDiscountStrategy();
}
 
//계산 버튼
public void onCalculationButtonClick(){
    Calculator cal = new Calculator(strategy);
    int price = cal.calculate(items);
}
cs

 

전략 패턴의 이점

콘텍스트 코드의 변경 없이 새로운 전략을 추가할 수 있다.

마지막 손님 대폭 할인을 추가하는 경우 DiscountStrategy 인터페이스를 상속하는 LastGuestDiscountStrategy 클래스를 만들어 할인 버튼에 추가만 해줘 객체를 생성해주기만 하면된다.

//마자막 손님 대폭 할인 버튼
public void onLastGuestButtonClick(){
     strategy = new LastGuestDiscountStrategy();
}

전략 패턴을 적용함으로 써 Calculator 클래스는 할인 정책 확장에는 열려 있고 변경에는 닫혀있게 된다.

즉, 개방 폐쇄 원칙을 따르는 구조이다.

 

 

출처:[교재] 개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴

728x90
반응형
LIST