Strategy Pattern 정리

luckyhan studio·2021년 5월 31일

자주 쓰이는 디자인 패턴중에 전략 패턴이 있다. 패턴 구조는 위 이미지와 같이 나타낼 수 있다. Context 클래스가 Strategy 클래스를 포함(Composition)하는 구조이고 Context가 Strategy의 setter를 가지고 있어 언제든 원하는 전략으로 코드 수정없이 변경 가능하다.

전략 패턴은 디자인 원칙중에 DRY(Don't repeat yourself)원칙과 OCP원칙을 만족한다. Context에서 새로운 기능(전략)이 필요하면 Context 코드를 수정하지 않고(Closure) 새로운 Strategy를 만들어(Open) 기능을 구현할 수 있다. 또한 Strategy 코드를 재사용할 수 있어 같은 전략을 사용하는 Concrete Context들 사이에서 코드가 반복되지 않는다.

코드가 반복되고 OCP에 위배되는 구현 예제와 이를 해결한 구현을 비교하면 쉽게 이해할 수 있다.

요즘 주식이 핫하니 주식 매수에 빗대어 전략 패턴을 응용해보자!

일단 주식을 하는 사람들은 저마다 매수 방법과 매도 방법이 있다. 이것을 코드로 표현하면 아래와 같다.

class StockTrader{
public:
	virtual void buy() = 0;
	virtual void sell() = 0;
};

class Chulsu : public StockTrader{
public:
	void buy(){
		cout << "by ROE" << endl;
	}
	void sell(){
		cout << "by target" << endl;
	}
};

class Minsu : public StockTrader{
public:
	void buy(){
		cout << "by PER" << endl;
	}
	void sell(){
		cout << "by target" << endl;
	}
};

철수는 단기투자 ROE 지표를 보고 매수를 목표가가 되면 매도한다. 민수는 PER 지표를 보고 매수하고 목표가가 되면 매도를 한다. 그런데 PER 지표를 보고 매수하는 민수가 ROE 지표를 보고 매수하는 철수보다 수익률이 좋았다. 그래서 철수도 PER 지표로 매수 전략을 바꾸려고 한다. 그러면 철수의 코드를 고쳐야 한다. 그럼 OCP에 위배 된다.

물론, 지금은 단순한 예를 들어서 그냥 고치는게 뭐가 대수인가 라고 생각할 수 있지만 코드가 복잡해지고 Context가 많아지면 더 복잡해 진다. 이런 부분은 프로젝트에서 경험해야 와 닿을 수 있다.

또한 목표가 매도 전략은 두 사람 모두 사용한다. 만약 목표가 전략을 수정해야 한다면 두 사람의 코드 모두 변경 해야 한다. 이 부분이 DRY 원칙에 위배되고 수정할 때 한쪽만 수정하거나 잘못 수정하면 버그가 발생할 확률이 높다. 그래서 이 문제를 Strategy Pattern을 사용해서 해결해보자.


class BuyStrategy{
public:
	virtual void buy() = 0;
};

class BuyRoe : public BuyStrategy{
	void buy(){
		cout << "by ROE" << endl;
	}
};


class BuyPer : public BuyStrategy{
	void buy(){
		cout << "by PER" << endl;
	}
};

class SellStrategy{
public:
	virtual void sell() = 0;
};

class SellTarget : public SellStrategy{
	void buy(){
		cout << "by target" << endl;
	}
};

class StockTrader{
private:
	SellStrategy* sellStrategy;
	BuyStrategy* buyStrategy;
public:
	void setBuyStrategy(BuyStrategy* buyStrategy){
		this->buyStrategy = buyStrategy;
	}
	void setSellStrategy(SellStrategy* sellStrategy){
		this->sellStrategy = sellStrategy;
	}

	void buy(){
		buyStrategy->buy();
	}
	void sell(){
		sellStrategy->sell();
	}
};

class Chulsu : public StockTrader{};

class Minsu : public StockTrader{};

위와 같이 코드를 변경 하면, 철수와 민수의 매매전략을 언제든 자유롭게 변경할 수 있고, PER, ROE 전략외에 다른 매수 전략도 BuyStrategy 클래스를 상속받아 추가할 수 있다. 최소한 Trader의 코드는 매수 매도 전략에 의해 변경될 일은 없어졌다. 또한 반복된 매도 방법에 대한 코드 또한 Sell 전략에 의해 재사용될 수 있게 됐다.

profile
열심히 사는 그냥 개발자

0개의 댓글