전략 패턴(Strategy Pattern)#
- 전략 패턴은 객체 내부에서 동적으로 알고리즘을 교체하기 위한 패턴입니다.
- 여기서 말하는 알고리즘이란 어떤 문제를 해결하기 위한 방법을 의미합니다.
- 따라서 어떤 문제를 해결하기 위한 함수 또는 로직을 객체로 분리하여 런타임 상황에서 교체하는 패턴입니다.
- 템플릿 메서드(Template Method)와 유사한 부분이 존재합니다.
- 템플릿 메서드는 하나의 알고리즘을 다양한 방식으로 재정의(오버라이딩)하여 행동을 분리하는 패턴입니다. 하지만 공통 템플릿도 수정해야할 경우 상위 클래스도 수정해야 하는 단점이 있습니다.
- 전략 패턴은 템플릿 메서드와는 다르게 행위의 전체를 변경할 때 사용하는 패턴입니다.
전략 패턴 구조#
- 알고리즘을 교체하기 위해서는 공통된 처리가 필요합니다.
- 따라서 알고리즘 인터페이스 클래스와 실제 구현체가 필요합니다.
- 또한 알고리즘 인터페이스를 이용하여 전략을 교체할 전략 추상 클래스와 실제 구현체가 필요합니다.
- 따라서 아래와 같이 정리할 수 있습니다.
- Algorithm
- ConcreteAlgorithm
- Strategy
- ConcreteStrategy
전략 패턴: 알고리즘 인터페이스 클래스#
- 알고리즘 교체를 위한 공통된 인터페이스 클래스를 선언합니다.
- 게임에서 캐릭터가 무기를 교체하여 사용하는 예제를 사용하겠습니다.
// Algorithm
class Weapon
{
public:
virtual void attack() = 0;
};
전략 패턴: 알고리즘 클래스 구현#
- 교체할 알고리즘들을 실제로 구현합니다.
- 공통된 인터페이스 클래스로 서로 다른 알고리즘을 갖고 있습니다.
// ConcreteAlgorithm
class Knife :
public Weapon
{
public:
void attack() override
{
std::cout << "[Knife] Attack()" << std::endl;
}
};
// ConcreteAlgorithm
class Gun :
public Weapon
{
public:
void attack() override
{
std::cout << "[Gun] Attack()" << std::endl;
}
};
전략 패턴: 전략 추상 클래스 구현#
- 알고리즘을 런타임 상황에서 교체할 추상 클래스가 필요합니다.
- 내부적으로 알고리즘 객체를 저장할 프로퍼티가 존재하고, 이를 지정하는
setWeapon()
메서드가 필요합니다.
class Strategy
{
public:
void setWeapon(std::shared_ptr<Weapon> weapon)
{
m_weapon = weapon;
}
virtual void attack() = 0;
protected:
std::shared_ptr<Weapon> m_weapon;
};
전략 패턴: 전략 클래스 구현#
- 전략 클래스의 실제적인 하위 클래스를 구현합니다.
- 알고리즘 인터페이스 클래스의 메서드를 호출하기 때문에 특정 알고리즘에 종속되지 않습니다.
// ConcreteStrategy
class Charactor :
public Strategy
{
public:
void attack()
{
if (m_weapon == nullptr)
{
std::cout << "[Charactor] attack() hand" << std::endl;
}
else
{
m_weapon->attack();
}
}
};
전략 패턴: 실행 코드#
- 전략 패턴은 구조가 간단하고 이해하기 쉽습니다.
- 동일한 USB 인터페이스를 통해 키보드, 마우스, 프린터 등 다양한 장치를 처리하는 알고리즘을 생각하면 그 구조를 쉽게 이해할 수 있습니다.
- 템플릿 메서드와 같이 많이 사용하는 패턴 중 하나입니다.
int main(const int argc, const char* argv[])
{
std::shared_ptr<Charactor> charactor = std::make_shared<Charactor>();
charactor->attack();
std::shared_ptr<Knife> knife = std::make_shared<Knife>();
charactor->setWeapon(knife);
charactor->attack();
std::shared_ptr<Gun> gun = std::make_shared<Gun>();
charactor->setWeapon(gun);
charactor->attack();
return 0;
}
[Charactor] attack() hand
[Knife] Attack()
[Gun] Attack()