[Design Pattern] 전략 패턴

Strategy Pattern

전략 패턴은 객체가 수행할 수 있는 행위 각각에 대한 전략 클래스를 생성하고 전략 클래스들의 공통된 인터페이스를 정의하는 패턴이다. 이렇게 함으로써 객체의 행위를 동적으로 바꿀 수 있으며 유연하게 확장할 수 있다.

활용성

  • 행동들이 조금 다르지만 개념적으로 관련된 많은 클래스들이 존재할 때
  • 알고리즘의 변형이 필요할 때
  • 사용자가 몰라야 하는 데이터를 사용하는 알고리즘이 있을 때
  • 하나의 클래스가 많은 행동을 정의하고 행동 내부에서 많은 조건문으로 분기를 나눌 때

전략 패턴 사용에 따른 결과

동일 계열 관련 전략 클래스 생성

전략 클래스는 동일 계열의 행동군을 정의한다. 이를 통해 객체의 재사용이 가능해진다.

서브클래싱을 사용하지 않음

상속은 전략을 바꾸기 위한 또 다른 방법이다. 하지만 상속을 통한 구현을 수행하게 되면 추후에 변경이나 확장에 어려움을 겪게 된다. 전략 패턴은 이를 방지해준다.

조건문의 삭제

원하는 행동을 수행하기 위해 함수 내에 존재하는 여러 조건문에 대해 행동을 캡슐화 함으로써 이를 삭제할 수 있다.

구현의 선택

전략 패턴을 사용함으로써 동일한 행동에 대한 다양한 구현을 선택할 수 있다.

전략에 대한 학습 필요

사용자가 자신의 상황에 맞는 적당한 전략을 선택하기 위해서 전략들에 대한 학습이 필요하다.

Strategy객체와 Context객체간 오버헤드

Strategy 인터페이스와 Strategy 객체는 높은 결합도를 가지고 있다. 그렇기 때문에 특정 전략의 경우에는 인터페이스에서 사용하는 모든 파라미터를 사용하지 않을 경우가 있는데, 이 때 Context 객체는 사용하지 않을 더미 데이터를 파라미터를 위해 사용해야할 경우가 생긴다.

전략

구조

전략의 구조는 다음과 같다.

Strategy Pattern Diagram

C++ 구현

1
2
3
4
5
6
7
8
9
10
void StrategyPattern::StrategyPattern()
{
Product* normalProduct = new Product(new NormalPriceStrategy, 10000);
Product* blackFridayProduct = new Product(new BlackFridayPriceStrategy, 10000);
Product* timeSaleProduct = new Product(new TimeSalePriceStrategy, 10000);

std::cout<<"normal product cost : "<<normalProduct->getPrice()<<std::endl;
std::cout<<"black friday product cost : "<<blackFridayProduct->getPrice()<<std::endl;
std::cout<<"time sale product cost : "<<timeSaleProduct->getPrice()<<std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
class Product
{
PriceStrategy* priceStrategy;
int price;
public:
Product(PriceStrategy* priceStrategy, int price) : priceStrategy(priceStrategy), price(price) {}

int getPrice()
{
return priceStrategy->pricePolicy(this->price);
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class PriceStrategy
{
public:
virtual ~PriceStrategy() {}
virtual int pricePolicy(int price) = 0;
};

class NormalPriceStrategy : public PriceStrategy
{
public:
~NormalPriceStrategy() {}
int pricePolicy(int price) override
{
return price;
}
};

class BlackFridayPriceStrategy : public PriceStrategy
{
public:
~BlackFridayPriceStrategy() {}
int pricePolicy(int price) override
{
return price * 0.5;
}
};

class TimeSalePriceStrategy : public PriceStrategy
{
public:
~TimeSalePriceStrategy() {}
int pricePolicy(int price) override
{
return price * 0.9;
}
};

java 구현

1
2
3
4
5
6
7
8
9
10
11
public class Client {
public static void main(String[] args) {
Product normalProduct = new Product(new NormalPriceStrategy(), 10000);
Product blackFridayProduct = new Product(new BlackFridayPriceStrategy(), 10000);
Product timeSaleProduct = new Product(new TimeSalePriceStrategy(), 10000);

System.out.println("normal product cost : " + normalProduct.getPrice());
System.out.println("black friday product cost : " + blackFridayProduct.getPrice());
System.out.println("time sale product cost : " + timeSaleProduct.getPrice());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Product {
private PriceStrategy priceStrategy;
private int price;

public Product(PriceStrategy priceStrategy, int price) {
this.priceStrategy = priceStrategy;
this.price = price;
}

public int getPrice() {
return priceStrategy.pricePolicy(price);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface PriceStrategy {
int pricePolicy(int price);
}

public class NormalPriceStrategy implements PriceStrategy{
@Override
public int pricePolicy(int price) {
return price;
}
}

public class BlackFridayPriceStrategy implements PriceStrategy{
@Override
public int pricePolicy(int price) {
return (int) (price * 0.5);
}
}

public class TimeSalePriceStrategy implements PriceStrategy{
@Override
public int pricePolicy(int price) {
return (int) (price * 0.9);
}
}
Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/30/Design%20Pattern/StrategyPattern/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.