디자인 패턴
전략 패턴 (Strategy Parttern)
DevHyo
2021. 9. 16. 18:46
전략 패턴이란 같은 기능이지만, 서로 다른 전략을 가진 클래스들을 캡슐화하여 상호 교환할 수 있도록 도와주는 디자인 패턴입니다.
전략 패턴 예시
현재 시스템은 VIP 회원에 대한 2,000원 할인을 해주는 정책을 기본적으로 제공하고 있으며, 상황에 따라 새로운 정책이 추가될 가능성이 높은 상황입니다. 아래의 코드를 보면서 전략 패턴을 설명하도록 하겠습니다.
회원 등급을 가지고 있는 Member 클래스
public class Member {
private final Long id;
private final String name;
private final Grade grade;
public enum Grade { BASIC, VIP }
public Member(Long id, String name) {
this.id = id;
this.name = name;
this.grade = Grade.BASIC;
}
void setGrade(Grade grade) {
this.grade = grade;
}
Grade getGrade() {
return grade;
}
}
DiscountPolicy 인터페이스를 통해 할인 금액 조회 기능을 제공한다.
public interface DiscountPolicy {
int getDiscountPrice(Member member, int price);
}
DiscountPolicy 인터페이스를 구현한 FixedDiscountPolicy 클래스
public class FixedDiscountPolicy implements DiscountPolicy {
@Override
public int getDiscountPrice(Member member, int price) {
if (member.getGrade() == Member.Grade.VIP) return 2_000;
return 0;
}
}
DiscountService 클래스를 통해 할인 정보를 반환한다.
public class DiscountService {
private final MemberFinder memberFinder;
public DiscountService(MemberFinder memberFinder) {
this.memberFinder = memberFinder;
}
public int getDiscountPrice(Long memberId, int price, DiscountPolicy discountPolicy) {
Member member = memberFinder.findById(memberId);
// 할인 정보를 반환
return discountPolicy.getDiscountPrice(member, price);
}
}
Client는 VIP 등급에 따라 할인을 받을 수 있는지 정보를 조회할 수 있다.
public class Client {
public static void main(String[] args) {
// 할인 정보 조회
Long memberId = 1;
int price = 10_000;
discountPolicy.getDiscountPrice(memberId, price, new FixedDiscountPolicy());
}
}
시간이 지나 VIP 등급에 대한 할인 정책이 비율 할인으로 변경되었고, 기존의 FixedDiscountPolicy는 더 이상 사용하지 않게 되었습니다. Client는 새롭게 추가되는 정책에 따라 변경된 할인 금액을 조회해야 하는 상황이 오게 되었는데, 전략 패턴을 사용하게 되면 전체적인 구조에서 큰 변화 없이 유지 보수가 가능하게 됩니다.
새롭게 추가된 RateDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {
private final int discountPercent = 10;
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Member.Grade.VIP) {
return price * discountPercent / 100;
}
return 0;
}
}
Client는 RateDiscountPolicy로 변경하면 된다.
public class Client {
public static void main(String[] args) {
// 할인 정보 조회
Long memberId = 1;
int price = 10_000;
// RateDiscountPolicy로 변경
discountPolicy.getDiscountPrice(memberId, price, new RateDiscountPolicy());
}
}
변경된 부분이 없는 DiscountService
public class DiscountService {
private final MemberFinder memberFinder;
public DiscountService(MemberFinder memberFinder) {
this.memberFinder = memberFinder;
}
public int getDiscountPrice(Long memberId, int price, DiscountPolicy discountPolicy) {
Member member = memberFinder.findById(memberId);
// 할인 정보를 반환
return discountPolicy.getDiscountPrice(member, price);
}
}
RateDiscountPolicy로 변경됐지만, DiscountService에서는 추가된 할인 정책과 상관없이 할인 금액 조회 기능을 정상적으로 수행하고 있으며, 로직을 수정할 필요도 없습니다. Client에서는 그저 RateDiscountPolicy를 사용하기만 하면 됩니다.
정리
위와 같은 예시를 통해 '할인 금액을 조회한다.'라는 공통 기능이 있지만, 상황에 따라 다른 전략인 FixedDiscountPolicy, RateDiscountPolicy가 상호 교환되는 부분을 확인할 수 있으며, 전략 패턴은 유지 보수하는 과정에서 변경을 최소화할 수 있는 장점을 가지고 있습니다.