전략 패턴
(C++ 소프트웨어 디자인 책 정리)
전략 디자인 패턴의 의도는 다음과 같다.
'알고리즘 군을 정의하고 각각을 캡슐화해 상호 교환이 가능하게 한다.
전략을 사용하면 알고리즘 사용하는 클라이언트와 독립적으로 알고리즘을 변경할 수 있다'
지난 visitor 패턴에서 사용한 주제로 전략 디자인 패턴을 UML로 표현하면 다음과 같다.
파생 클래스에서 가상의 draw() 함수를 구현하는 대신 여러분은 도형 그리기를 위해 다른 클래스를 도입한다.
전략 디자인 패턴의 고전적인 객체 지향 형식의 경우 DrawStrategy기본 클래스를 도입해 이를 해낸다.
위 UML처럼 그리기 관심사의 격리로 이제 도형 클래스를 수정하지 않고 그리기 구현을 변경할 수 있다.
//----- <DrawStrategy.h> ------
class Circle;
class Square;
class DrawStrategy
{
public:
virtual ~DrawStrategy() = default;
virtual void draw( Circle const& circle, /* 몇몇 인자 */ ) const = 0;
virtual void draw( Square const& square, /* 몇몇 인자 */ ) const = 0;
};
//----- <Shape.h> ------
class Shape
{
public:
virtual ~Shape() = default;
virtual void draw( /* 몇몇 인자 */) const = 0;
// ...Etc method
};
Shape 기초 클래스는 전략 디자인 패턴으로 인해 변경되지 않으며, 여전히 모든 도형에 대한 추상화를 나타내므로 순수 가상 draw() 멤버 함수를 제공한다. 전략은 구현 상세 추출을 목표로 하므로 파생 클래스에만 영향을 미친다.
Shape 기초 클래스는 전략으로 인해 바뀌지 않지만, Circle등 Shape를 상속받는 클래스는 영향을 받는다.
//---- <Circle.h> ---------
#include <Shape.h>
#include <DrawStrategy.h>
class Circle : public Shape
{
private:
std::unique_ptr<DrawStrategy> drawer_;
public:
explicit Circle( double radius, std::unique_ptr<DrawStrategy> strategy) {
/* 조건 검사 */
}
void draw() override {
drawer_->draw(*this);
}
};
Circle은 이제 생성자에서 DrawStrategy 에 대한 unique_ptr을 기대하고 있다. 이를 통해 흔히 의존성 주입 이라고 하는, 외부에서 그리기 행위를 설정할 수 있다. unique_ptr은 타입이 같은 새 데이터 멤버로 이동한다. 또한 나중에 그리기 행위를 바꿀 수 있는 상응하는 설정함수를 제공할 수도 있다. 이제 draw() 멤버 함수는 그리기 자체를 구현할 필요가 없고 단순히 주어진 DrawStrategy에 대해 draw()함수를 호출하면 된다.
하지만 위 전략 패턴을 아키텍처 관점에서 봤을 때 DrawStrategy 를 상속받는 클래스들은 DrawStrategy 기초클르새를 통해 모든 도형이 암시적으로 서로에 대해 알기 때문에 ISP 원칙 위반이다.
AS-IS
위 디자인 패턴에서 클래스 템플릿을 이용하여 DrawStrategy 를 더 상위 아키텍처로 옮기고 양쪽 사용 방향을 한방향으로 변경한다.
TO-BE
//----- <DrawStrategy.h> -------
template< typename T >
class DrawStrategy
{
public:
virtual ~DrawStrategy() = default;
virtual void draw( T &) = 0;
};
//----- <OpenGLStrategy.h> -------
#include "DrawStrategy.h"
class Circle;
class OpenGLCircleStrategy : public DrawStrategy<Circle>
{
private:
// ...OpenGL 에 필요한 변수, 메서드
public:
// ...생성자등 OpenGL에 필요한 변수, 메서드
void draw( Circle& c) override {
// ... OpenGL을 활용한 drawing ...
}
};
//---- <Circle.h> ---------
#include <Shape.h>
#include <DrawStrategy.h>
class Circle : public Shape
{
private:
std::unique_ptr<DrawStrategy<Circle>> drawer_;
public:
explicit Circle( double radius, std::unique_ptr<DrawStrategy<Circle>> strategy) {
/* 조건 검사 */
}
void draw() override {
drawer_->draw(*this);
}
};
github 코드: https://github.com/KJT9109/designPattern.git
'Language > C++ Design Pattern' 카테고리의 다른 글
Command 패턴 (0) | 2025.02.12 |
---|---|
Visitor 패턴 (std::variant) (0) | 2025.02.05 |
Visitor 패턴 (1) | 2025.02.02 |
DIP 원칙 (0) | 2025.01.30 |
LSP 원칙 (0) | 2025.01.30 |