2 minute read

스트레티지(Stratigy) 패턴이란?


스트래티지 패턴은 실행 시간에 알고리즘을 선택할 수 있도록 하는 행위 디자인 패턴입니다.
즉, 동일한 작업을 수행하는 여러 알고리즘을 클래스로 캡슐화하고, 필요에 따라 이들을 교체하여 사용할 수 있도록 합니다. 마치 여행을 갈 때 상황에 따라 다른 교통수단을 선택하는 것과 같습니다. 가까운 거리는 걸어가고, 먼 거리는 자동차나 비행기를 이용하는 것처럼, 스트래티지 패턴은 상황에 맞는 알고리즘을 선택하여 효율적인 작업을 수행할 수 있도록 합니다.



스트레티지(Stratigy) 패턴의 구성 요소


  • Context (컨텍스트): 클라이언트가 사용하는 객체로, 스트래티지 객체에 대한 참조를 가지고 있습니다. 컨텍스트는 실제 알고리즘을 수행하는 역할을 스트래티지 객체에 위임합니다.
  • Strategy (스트래티지 인터페이스): 모든 구체적인 스트래티지 클래스가 구현해야 하는 인터페이스 또는 추상 클래스입니다. 알고리즘을 정의하는 메서드를 선언합니다.
  • Concrete Strategy (구체적인 스트래티지): 실제 알고리즘을 구현하는 클래스입니다. 스트래티지 인터페이스를 구현합니다.

스트레티지(Stratigy) 패턴의 작동 방식


  1. 클라이언트는 컨텍스트 객체를 생성하고, 사용할 스트래티지 객체를 선택하여 컨텍스트에 전달합니다.
  2. 컨텍스트는 클라이언트의 요청을 받으면, 자신이 가지고 있는 스트래티지 객체의 메서드를 호출하여 실제 알고리즘을 수행합니다.
  3. 필요에 따라 클라이언트는 컨텍스트에 다른 스트래티지 객체를 전달하여 알고리즘을 변경할 수 있습니다.

스트레티지(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;
}


Top