전략 패턴 활용하기

전략 패턴은 알고리즘 집합을 정의하고 각각을 캡슐화하여 상호 교체가 가능하도록 만드는 방법이다. 이 패턴은 알고리즘 변경이 클라이언트에 영향을 주지 않도록 설계되었다.

다음은 전략 패턴을 구현하는 기본적인 코드 예제이다.

1. 전략 인터페이스 정의

알고리즘을 처리할 공통 인터페이스를 정의한다.

public abstract class AlgorithmStrategy
{
    public abstract void Execute();
}

2. 구체적인 전략 클래스

각각의 알고리즘을 구현한 클래스들을 정의한다.

public class StrategyA : AlgorithmStrategy
{
    public override void Execute()
    {
        Console.WriteLine("전략 A 실행");
    }
}

public class StrategyB : AlgorithmStrategy
{
    public override void Execute()
    {
        Console.WriteLine("전략 B 실행");
    }
}

public class StrategyC : AlgorithmStrategy
{
    public override void Execute()
    {
        Console.WriteLine("전략 C 실행");
    }
}

3. 컨텍스트 클래스

컨텍스트는 특정 전략을 선택하고 해당 전략의 메서드를 호출하는 역할을 수행한다.

public class ContextManager
{
    private AlgorithmStrategy _strategy;

    public ContextManager(AlgorithmStrategy strategy)
    {
        _strategy = strategy;
    }

    public void ApplyStrategy()
    {
        _strategy.Execute();
    }
}

4. 클라이언트 코드

클라이언트에서는 어떤 전략을 사용할지 선택하고 실행할 수 있다.

class Program
{
    static void Main(string[] args)
    {
        var context = new ContextManager(new StrategyA());
        context.ApplyStrategy();

        context = new ContextManager(new StrategyB());
        context.ApplyStrategy();

        context = new ContextManager(new StrategyC());
        context.ApplyStrategy();
    }
}

단순 팩토리 적용

클라이언트에서 직접 전략을 선택하는 부분을 단순 팩토리로 개선할 수 있다.

public class ContextManager
{
    private AlgorithmStrategy _strategy;

    public ContextManager(string strategyType)
    {
        switch (strategyType.ToUpper())
        {
            case "A":
                _strategy = new StrategyA();
                break;
            case "B":
                _strategy = new StrategyB();
                break;
            case "C":
                _strategy = new StrategyC();
                break;
            default:
                throw new ArgumentException("지원하지 않는 전략입니다.");
        }
    }

    public void ApplyStrategy()
    {
        _strategy.Execute();
    }
}

클라이언트 코드는 다음과 같이 간단해진다.

var context = new ContextManager("A");
context.ApplyStrategy();

context = new ContextManager("B");
context.ApplyStrategy();

리플렉션과 설정 파일 활용

더 나아가, 리플렉션과 설정 파일을 사용하여 유연성을 높일 수 있다.

public class ContextManager
{
    private AlgorithmStrategy _strategy;

    public ContextManager(string strategyName)
    {
        var type = Type.GetType($"Namespace.{strategyName}");
        _strategy = (AlgorithmStrategy)Activator.CreateInstance(type);
    }

    public void ApplyStrategy()
    {
        _strategy.Execute();
    }
}

설정 파일(app.config)에는 다음과 같이 정의한다.

<appSettings>
    <add key="Strategy" value="StrategyA"/>
</appSettings>

클라이언트 코드는 설정 값을 읽어와 동적으로 전략을 결정한다.

string strategyName = ConfigurationManager.AppSettings["Strategy"];
var context = new ContextManager(strategyName);
context.ApplyStrategy();

C++ 버전 예제

다음은 C++에서 전략 패턴을 구현한 예제이다.

1. 전략 인터페이스 정의

#include <iostream>
using namespace std;

class Strategy
{
public:
    virtual void Perform() = 0;
};

2. 구체적인 전략 클래스

class ConcreteStrategyA : public Strategy
{
public:
    void Perform() override { cout << "전략 A 수행" << endl; }
};

class ConcreteStrategyB : public Strategy
{
public:
    void Perform() override { cout << "전략 B 수행" << endl; }
};

class ConcreteStrategyC : public Strategy
{
public:
    void Perform() override { cout << "전략 C 수행" << endl; }
};

3. 컨텍스트 클래스

class Context
{
private:
    Strategy* _strategy;

public:
    Context(Strategy* strategy) : _strategy(strategy) {}
    ~Context() { delete _strategy; }

    void ExecuteStrategy()
    {
        _strategy->Perform();
    }
};

4. 클라이언트 코드

int main()
{
    Context ctx(new ConcreteStrategyA());
    ctx.ExecuteStrategy();

    ctx = Context(new ConcreteStrategyB());
    ctx.ExecuteStrategy();

    return 0;
}

태그: C# DesignPatterns StrategyPattern

6월 3일 17:48에 게시됨