전략 패턴
동일 계열의 알고리즘군을 정의, 캡슐화하고 이를 사용하는 클라이언트와 상관없이 독립적으로 알고리즘을 서로 교환해서 사용할 수 있다.
사용하는 이유
만약 텍스트 스트림을 라인으로 구분하는 기능(다수 알고리즘이 있음)이 필요하다고 했을 때, 이 알고리즘들을 클래스에 하드코딩하는 것은 하기 이유로 바람직하지 않다.
- 기능에 대한 구현이 아닌 줄 분리 코드가 반복적으로 생김으로써 소스가 복잡해짐
- 때에 따라서 필요한 알고리즘이 다르기 때문에 모든 알고리즘을 제공할 필요가 없음
- 서비스로직과 줄 분리 알고리즘이 합쳐져 있으면 알고리즘 로직을 추상화시켜서 확장 시키기 어려움
- 위 문제 해결을 위해서 서비스로직과 각각의 줄 분리 알고리즘을 하나씩 캡슐화 한 클래스를 따로 정의하고 이 캡슐화된 알고리즘을 전략이라고 지칭한다.
구조
비슷한 계열의 알고리즘을 가지는 Strategy 인터페이스를 구현하는 N개의 전략 객체가 있고 Context(서비스로직)에서는 concrete한 전략 객체(알고리즘) 인스턴스를 주입받아서 직접 알고리즘 로직을 호출한다.
장단점
- 장점
- 코드 중복 방지
- 런타임 시에 타겟 메서드 변경 가능
- 동일 계열 알고리즘군을 정의했기 때문에 확장성, 재사용성이 높음
- 단점
- 여러 전략을 사용하는 케이스가 다 다르므로 이를 이해하고 있어야함
- 전략의 복잡도와는 상관없이 Strategy객체는 Context객체에서 전달하는 미사용 매개변수를 받아야함
예제 코드
// Strategy 인터페이스
interface BillingStrategy{
double GetActPrice(double rawPrice);
}
// 전략1 : Normal billing strategy (unchanged price)
class NormalStrategy implements BillingStrategy{
public double GetActPrice(double rawPrice){
return rawPrice;
}
}
// 전략2 : Strategy for Happy hour (50% discount)
class HappyHourStrategy implements BillingStrategy{
public double GetActPrice(double rawPrice){
return rawPrice * 0.5;
}
}
// Context
class Customer{
private List<Double> drinks;
public BillingStrategy strategy;
public Customer(BillingStrategy strategy){
this.drinks = new ArrayList<>();
this.strategy = strategy;
}
// 전략 패턴 사용
public void Add(double price, int quantity){
drinks.add(strategy.GetActPrice(price * quantity));
}
// Payment of bill
public void PrintBill(){
double sum = 0;
for(Double i : drinks){
sum += i;
}
System.out.println(("Total due: " + sum));
drinks.clear();
}
}interface BillingStrategy{
double GetActPrice(double rawPrice);
}
// 전략1 : Normal billing strategy (unchanged price)
class NormalStrategy implements BillingStrategy{
public double GetActPrice(double rawPrice){
return rawPrice;
}
}
// 전략2 : Strategy for Happy hour (50% discount)
class HappyHourStrategy implements BillingStrategy{
public double GetActPrice(double rawPrice){
return rawPrice * 0.5;
}
}
public class StrategyMain {
public static void main(String[] args){
Customer firstCustomer = new Customer(new NormalStrategy());
// Normal billing
firstCustomer.Add(1.0, 1);
// Start Happy Hour
firstCustomer.strategy = new HappyHourStrategy();
firstCustomer.Add(1.0, 2);
// New Customer
Customer secondCustomer = new Customer(new HappyHourStrategy());
secondCustomer.Add(0.8, 1);
// The Customer pays
firstCustomer.PrintBill();
// End Happy Hour
secondCustomer.strategy = new NormalStrategy();
secondCustomer.Add(1.3, 2);
secondCustomer.Add(2.5, 1);
secondCustomer.PrintBill();
}
}
/*
firstCustomer -> Total due : 2.0
secondCustomer -> Total due : 5.5
*/
참고 자료
- GoF의 디자인 패턴 (개정판)
- https://niceman.tistory.com/133
- https://ko.wikipedia.org/wiki/전략_패턴
'디자인패턴' 카테고리의 다른 글
[GoF의 디자인 패턴] 빌더 패턴 (0) | 2022.03.06 |
---|---|
[GoF의 디자인 패턴] 추상 팩토리 패턴 (0) | 2022.03.04 |
[GoF의 디자인 패턴] 싱글톤 패턴 (0) | 2022.03.01 |
[GoF의 디자인 패턴] 어댑터 패턴 (0) | 2021.11.21 |
[GoF의 디자인 패턴] 팩토리 메서드 (0) | 2020.05.10 |