본문 바로가기
-----ETC-----/C++ 고급 프로그래밍과 응용 프로젝트 시리즈

[C++ 고급 프로그래밍과 응용 프로젝트 시리즈] Day 10: 디자인 패턴 심화 - 전략 패턴 (Strategy Pattern)

by cogito21_cpp 2024. 8. 1.
반응형

전략 패턴 (Strategy Pattern)

전략 패턴은 행위 패턴 중 하나로, 알고리즘을 각각의 클래스에 캡슐화하여, 클라이언트가 알고리즘을 독립적으로 변경할 수 있도록 합니다. 이를 통해 알고리즘의 변화가 클라이언트 코드에 영향을 미치지 않도록 합니다.

 

전략 패턴의 특징

  1. 알고리즘 캡슐화: 알고리즘을 독립적인 클래스로 캡슐화하여 교체가 용이합니다.
  2. 유연성 제공: 런타임에 알고리즘을 동적으로 변경할 수 있습니다.
  3. 클래스 분리: 클라이언트 코드와 알고리즘 클래스를 분리하여 코드의 가독성과 유지보수성을 높입니다.

전략 패턴의 구조

  1. Context: 전략을 사용하는 클래스
  2. Strategy: 알고리즘을 정의하는 인터페이스
  3. ConcreteStrategy: 구체적인 알고리즘을 구현하는 클래스

전략 패턴 UML 다이어그램

+-----------+       +------------+
|   Context |       |  Strategy  |
|-----------|       |------------|
| -strategy |<----->| +algorithm |
+-----------+       +------------+
      |
      | uses
      |
      v
+-----------------+
| ConcreteStrategy|
|-----------------|
| +algorithm      |
+-----------------+

전략 패턴 구현 예제

다음 예제는 전략 패턴을 사용하여 다양한 정렬 알고리즘을 구현합니다.

 

전략 인터페이스 정의

#include <iostream>
#include <vector>
#include <algorithm>

// 전략 인터페이스
class SortStrategy {
public:
    virtual void sort(std::vector<int>& data) = 0;
    virtual ~SortStrategy() = default;
};

 

구체적인 전략 클래스 구현

// 버블 정렬 전략
class BubbleSort : public SortStrategy {
public:
    void sort(std::vector<int>& data) override {
        for (size_t i = 0; i < data.size() - 1; ++i) {
            for (size_t j = 0; j < data.size() - i - 1; ++j) {
                if (data[j] > data[j + 1]) {
                    std::swap(data[j], data[j + 1]);
                }
            }
        }
    }
};

// 선택 정렬 전략
class SelectionSort : public SortStrategy {
public:
    void sort(std::vector<int>& data) override {
        for (size_t i = 0; i < data.size() - 1; ++i) {
            size_t min_idx = i;
            for (size_t j = i + 1; j < data.size(); ++j) {
                if (data[j] < data[min_idx]) {
                    min_idx = j;
                }
            }
            std::swap(data[i], data[min_idx]);
        }
    }
};

// 삽입 정렬 전략
class InsertionSort : public SortStrategy {
public:
    void sort(std::vector<int>& data) override {
        for (size_t i = 1; i < data.size(); ++i) {
            int key = data[i];
            size_t j = i - 1;
            while (j >= 0 && data[j] > key) {
                data[j + 1] = data[j];
                --j;
            }
            data[j + 1] = key;
        }
    }
};

 

Context 클래스 정의

// Context 클래스
class SortContext {
private:
    SortStrategy* strategy;

public:
    SortContext(SortStrategy* strategy) : strategy(strategy) {}

    void setStrategy(SortStrategy* newStrategy) {
        strategy = newStrategy;
    }

    void sort(std::vector<int>& data) {
        strategy->sort(data);
    }
};

 

전략 패턴 사용 예제

int main() {
    std::vector<int> data = {5, 2, 9, 1, 5, 6};

    BubbleSort bubbleSort;
    SelectionSort selectionSort;
    InsertionSort insertionSort;

    SortContext context(&bubbleSort);
    context.sort(data);
    std::cout << "Bubble Sort: ";
    for (int num : data) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    data = {5, 2, 9, 1, 5, 6};
    context.setStrategy(&selectionSort);
    context.sort(data);
    std::cout << "Selection Sort: ";
    for (int num : data) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    data = {5, 2, 9, 1, 5, 6};
    context.setStrategy(&insertionSort);
    context.sort(data);
    std::cout << "Insertion Sort: ";
    for (int num : data) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

 

이 예제에서 SortContext 클래스는 다양한 정렬 알고리즘을 사용하여 데이터를 정렬합니다. SortStrategy 인터페이스를 통해 다양한 정렬 전략을 정의하고, SortContext는 런타임에 전략을 변경하여 데이터를 정렬할 수 있습니다.


실습 문제

문제 1: 전략 패턴을 사용하여 다양한 검색 알고리즘 구현

전략 패턴을 사용하여 선형 검색과 이진 검색을 구현하고, 런타임에 검색 알고리즘을 선택하여 데이터를 검색하는 프로그램을 작성하세요.

 

해설:

전략 인터페이스 정의

#include <iostream>
#include <vector>

// 검색 전략 인터페이스
class SearchStrategy {
public:
    virtual int search(const std::vector<int>& data, int target) = 0;
    virtual ~SearchStrategy() = default;
};

 

구체적인 전략 클래스 구현

// 선형 검색 전략
class LinearSearch : public SearchStrategy {
public:
    int search(const std::vector<int>& data, int target) override {
        for (size_t i = 0; i < data.size(); ++i) {
            if (data[i] == target) {
                return i;
            }
        }
        return -1;
    }
};

// 이진 검색 전략
class BinarySearch : public SearchStrategy {
public:
    int search(const std::vector<int>& data, int target) override {
        size_t left = 0;
        size_t right = data.size() - 1;
        while (left <= right) {
            size_t mid = left + (right - left) / 2;
            if (data[mid] == target) {
                return mid;
            } else if (data[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }
};

 

Context 클래스 정의

// Context 클래스
class SearchContext {
private:
    SearchStrategy* strategy;

public:
    SearchContext(SearchStrategy* strategy) : strategy(strategy) {}

    void setStrategy(SearchStrategy* newStrategy) {
        strategy = newStrategy;
    }

    int search(const std::vector<int>& data, int target) {
        return strategy->search(data, target);
    }
};

 

전략 패턴 사용 예제

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    LinearSearch linearSearch;
    BinarySearch binarySearch;

    SearchContext context(&linearSearch);
    int target = 5;
    int index = context.search(data, target);
    std::cout << "Linear Search: Element " << target << " found at index " << index << std::endl;

    context.setStrategy(&binarySearch);
    index = context.search(data, target);
    std::cout << "Binary Search: Element " << target << " found at index " << index << std::endl;

    return 0;
}

 

이제 10일차의 학습을 마쳤습니다. 전략 패턴의 다양한 구현 방법과 활용 사례에 대해 상세히 학습하고 실습 문제를 풀어보았습니다.

 

질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "옵저버 패턴"에 대해 학습하겠습니다.

반응형