[Design Pattern] 스트레티지 패턴(Stratigy Pattern)의 기본 개념 정리 (C++ 샘플코드 포함)
스트레티지(Stratigy) 패턴이란?
스트래티지 패턴은 실행 시간에 알고리즘을 선택할 수 있도록 하는 행위 디자인 패턴입니다.
즉, 동일한 작업을 수행하는 여러 알고리즘을 클래스로 캡슐화하고, 필요에 따라 이들을 교체하여 사용할 수 있도록 합니다. 마치 여행을 갈 때 상황에 따라 다른 교통수단을 선택하는 것과 같습니다. 가까운 거리는 걸어가고, 먼 거리는 자동차나 비행기를 이용하는 것처럼, 스트래티지 패턴은 상황에 맞는 알고리즘을 선택하여 효율적인 작업을 수행할 수 있도록 합니다.
스트레티지(Stratigy) 패턴의 구성 요소
- Context (컨텍스트): 클라이언트가 사용하는 객체로, 스트래티지 객체에 대한 참조를 가지고 있습니다. 컨텍스트는 실제 알고리즘을 수행하는 역할을 스트래티지 객체에 위임합니다.
- Strategy (스트래티지 인터페이스): 모든 구체적인 스트래티지 클래스가 구현해야 하는 인터페이스 또는 추상 클래스입니다. 알고리즘을 정의하는 메서드를 선언합니다.
- Concrete Strategy (구체적인 스트래티지): 실제 알고리즘을 구현하는 클래스입니다. 스트래티지 인터페이스를 구현합니다.
스트레티지(Stratigy) 패턴의 작동 방식
- 클라이언트는 컨텍스트 객체를 생성하고, 사용할 스트래티지 객체를 선택하여 컨텍스트에 전달합니다.
- 컨텍스트는 클라이언트의 요청을 받으면, 자신이 가지고 있는 스트래티지 객체의 메서드를 호출하여 실제 알고리즘을 수행합니다.
- 필요에 따라 클라이언트는 컨텍스트에 다른 스트래티지 객체를 전달하여 알고리즘을 변경할 수 있습니다.
스트레티지(Stratigy) 패턴의 장단점
장점
- 알고리즘의 캡슐화: 각 알고리즘을 별도의 클래스로 캡슐화함으로써 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.
- 알고리즘의 교체 용이: 실행 시간에 알고리즘을 쉽게 변경할 수 있으므로, 유연한 설계를 가능하게 합니다.
- OCP (Open/Closed Principle) 준수: 새로운 알고리즘을 추가하더라도 기존 코드를 수정할 필요가 없으므로, OCP를 준수합니다.
- 알고리즘 선택의 유연성: 클라이언트는 필요에 따라 적절한 알고리즘을 선택하여 사용할 수 있습니다.
단점
- 클라이언트가 모든 스트래티지를 알아야 합니다.
- 스트래티지 클래스가 많아지면 관리가 어려워질 수 있습니다.
예시코드
#include <iostream>
#include <vector>
#include <algorithm>
// 스트래티지 인터페이스
class SortStrategy {
public:
virtual void Sort(std::vector<int>& data) = 0;
virtual ~SortStrategy() {}
};
// 구체적인 스트래티지: 버블 정렬
class BubbleSort : public SortStrategy {
public:
void Sort(std::vector<int>& data) override {
std::cout << "Using Bubble Sort" << std::endl;
// 버블 정렬 구현 (간략화)
for (int i = 0; i < data.size() - 1; ++i) {
for (int j = 0; j < data.size() - i - 1; ++j) {
if (data[j] > data[j + 1]) {
std::swap(data[j], data[j + 1]);
}
}
}
}
};
// 구체적인 스트래티지: std::sort 사용
class StdSort : public SortStrategy {
public:
void Sort(std::vector<int>& data) override {
std::cout << "Using std::sort" << std::endl;
std::sort(data.begin(), data.end());
}
};
// 컨텍스트
class Sorter {
private:
SortStrategy* strategy_;
public:
Sorter(SortStrategy* strategy) : strategy_(strategy) {}
void SetStrategy(SortStrategy* strategy) {
delete strategy_; // 기존 strategy 삭제 (메모리 누수 방지)
strategy_ = strategy;
}
void SortData(std::vector<int>& data) {
strategy_->Sort(data);
}
~Sorter(){
delete strategy_;
}
};
int main() {
std::vector<int> data = {5, 2, 8, 1, 9, 4};
// 버블 정렬 사용
Sorter sorter(new BubbleSort());
sorter.SortData(data);
for (int val : data) std::cout << val << " ";
std::cout << std::endl;
data = {5, 2, 8, 1, 9, 4}; // 데이터 초기화
// std::sort 사용
sorter.SetStrategy(new StdSort());
sorter.SortData(data);
for (int val : data) std::cout << val << " ";
std::cout << std::endl;
return 0;
}