if-else
문으로 분기 되어야 하고 이는 결과적으로 코드 분석과 유지보수를 어렵게 만든다. 기능을 사용하는 부분
과 구현하는 부분
을 명확히 분리하는 것이 중요하다.if-else
문으로 분기를 해줘야 하고, 이는 서로 다른 가격 정책들이 한 곳에 밀집되어있어 가독성이 떨어지게 된다.public class Calculator {
public int calculate(boolean firstGuest, List<Item> items) {
int sum = 0;
for (Item item : items) {
if (firstGuest) {
sum += (int) (item.getPrice() * 0.9);
} else if (! item.isFresh()) {
sum += (int) (item.getPrice * 0.8);
} else {
sum += item.getPrice();
}
}
return sum;
}
}
DiscountStrategy
라는 이름의 타입으로 추상화를 하고 각각의 할인된 가격을 반환하게 한다면 정책에 대한 구현과 사용에 대한 책임을 명확히 분리할 수 있다.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;
}
}
DiscountStrategy
라는 인터페이스를 구현한다.// 첫 손님 할인 정책
public class FirstGuestDiscountStrategy implemensts DiscountStrategy {
@Override
public int getDiscount(Item item) {
return (int) (item.getPrice() * 0.9);
}
}
// 덜 신선한 과일 할인 정책
public class NonFreshItemDiscountStrategy implemensts DiscountStrategy {
@Override
public int getDiscount(Item item) {
return (int) (item.getPrice() * 0.8);
}
}
단일 책임 원칙(SRP)
를 따른다고 볼 수 있다.개방 폐쇄 원칙(OCP)
도 따르는 구조를 갖게 된다.리스코프 치환 원칙(LSP)
도 잘 지켜진다고 볼 수 있다.인터페이스 분리 원칙(ISP)
도 따르고 있다.의존성 역전 원칙(DIP)
도 잘 따르고 있다고 할 수 있다.전략 패턴은 디자인 패턴 중에서도 많이 사용되는 패턴에 속한다.
전략 패턴을 사용하면 기본적으로 코드 중복 방지
, 런타임 시점에 메서드 변경
및 기능 확장이 용이
하다는 장점을 얻을 수 있다. 또한 결과적으로 위에서 언급한만큼 객체 지향 설계 원칙인 SOLID도 잘 따르는 구조를 가질 수 있기 때문에 기능이 많이 추가되고 수정되면서 많은 장점을 체감할 수 있을 것이다.
개발 도중에 많은 양의 if-else 코드를 발견했다면, 전략 패턴을 사용해서 리팩토링할 수 없는지 고민해보자. 코드가 훨씬 깔끔해지고 더욱 객체 지향적인 구조를 가져갈 수 있을 것이라 생각한다.