전략 패턴은 알고리즘 집합을 정의하고 각각을 캡슐화하여 상호 교체가 가능하도록 만드는 방법이다. 이 패턴은 알고리즘 변경이 클라이언트에 영향을 주지 않도록 설계되었다.
다음은 전략 패턴을 구현하는 기본적인 코드 예제이다.
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;
}