2022-04-07 @이영훈
전략 (Strategy) 패턴
The strategy pattern is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.
- wiki
알고리즘 그룹에서 어떤 알고리즘을 사용할 지 런타임에 선택할 수 있게 해주는 패턴입니다.
DIP (Dependency Inversion Principal)이랑 느낌이 비슷합니다.
빵집 할인 예제
고정할인과 퍼센트할인이 있습니다. 빵집이 오늘 오픈을 해서 2천원 할인 이벤트를 했습니다. 그리고 저녁에 마감 때 50% 할인 이벤트를 했습니다.
전체적인 구조는 다음과 같습니다.
빵집 할인 예제 - 코드 작성
우선 할인 전략 인터페이스를 작성합니다
️ support 함수로 어떤 할인정책을 선택할 지 정합니다
public interface DiscountPolicy {
public boolean support(LocalTime time);
public int discount(int itemPrice);
}
Java
복사
할인 전략 인터페이스를 구현하여 퍼센트 할인 전략과 고정 할인 전략을 구현합니다
퍼센트 할인 전략입니다.
public class PercentDiscountPolicy implements DiscountPolicy {
private final int discountPercent;
public PercentDiscountPolicy(int discountPercent) {
this.discountPercent = discountPercent;
}
@Override
public boolean support(LocalTime time) {
return time.isAfter(LocalTime.of(20, 0, 0));
}
@Override
public int discount(int itemPrice) {
// 퍼센트 할인시 생기는 소수점 자리는 버림 처리
return (int) (itemPrice * discountPercent * 0.01);
}
}
Java
복사
고정 할인 전략입니다.
public class FixAmountDiscountPolicy implements DiscountPolicy {
private final int discountAmount;
public FixAmountDiscountPolicy(int discountAmount) {
this.discountAmount = discountAmount;
}
@Override
public boolean support(LocalTime time) {
return time.isBefore(LocalTime.of(20, 0, 0));
}
@Override
public int discount(int itemPrice) {
return discountAmount;
}
}
Java
복사
마지막으로 할인 전략을 사용하는 가격 계산기를 만듭니다.
가격 계산기는 DiscountPolicy 인터페이스를 사용하고 구현체를 사용하지 않습니다.
할인 전략 구현체는 런타임에서 넣어서 사용합니다.
️ routing 함수를 통해서 적합한 할인전략을 선택합니다
public class PriceCalculator {
private final List<DiscountPolicy> discountPolicies;
public PriceCalculator(List<DiscountPolicy> discountPolicies) {
this.discountPolicies = discountPolicies;
}
public int getDiscountedPrice(List<Integer> items) {
int totalPrice = items.stream().reduce(0, Integer::sum);
DiscountPolicy discountPolicy = routingDiscountPolicy();
int totalDiscount = discountPolicy.discount(totalPrice);
return totalPrice - totalDiscount;
}
// ⭐️ routing 함수를 통해서 적합한 할인전략을 선택합니다
private DiscountPolicy routingDiscountPolicy() {
LocalTime now = LocalTime.now();
return discountPolicies.stream()
.filter(discountPolicy -> discountPolicy.support(now))
.findFirst()
.orElseThrow(() -> new RuntimeException("There is no matching discount policy"));
}
}
Java
복사
빵집 할인 예제 - 코드 실행
정책을 변경하는 코드가 없어도 시간이 지나면 자동으로 할인 가격 정책이 변경돼서 가격에 반영되는 것을 알 수 있습니다.
import java.util.Arrays;
import java.util.List;
public class StrategyApplication {
public static void main(String[] args) {
PriceCalculator priceCalculator = new PriceCalculator(Arrays.asList(
new PercentDiscountPolicy(50),
new FixAmountDiscountPolicy(2_000)
));
List<Integer> itemPrices = Arrays.asList(1000, 2000, 3000);
// 🌞 오전: 오픈 기념 2천원 정액할인 (저녁 10시 이전)
int morningPrice = priceCalculator.getDiscountedPrice(itemPrices);
System.out.println("morningPrice = " + morningPrice); // morningPrice = 4000
// ⌛️ 같은 코드를 시간이 지나서 저녁 10시가 되었다고 가정...
// 🌜 저녁: 마감 50% 할인 (저녁 10시 이후)
int nightPrice = priceCalculator.getDiscountedPrice(itemPrices);
System.out.println("nightPrice = " + nightPrice); // nightPrice = 3000
}
}
Java
복사