본문 바로가기

Coding Note

[Design pattern] Strategy

Strategy Pattern : 행동은 상황에 따라 달라질 수 있다. 하지만 여러 상황에 대해 행동을 분리한다면 수많은 조건절로 코드가 복잡해지게되고, 조건에 따른 행동의 결합도가 심히 높아질것이다. 이때 행동을 캡슐화 해두어서 행동을 사용하는 클래스와 행동을 정의하는 클래스를 분리시켜둔 뒤 사용하는 측에서 전략적으로 행동을 바꾸게 하여 문제를 해결할 수 있는데, 이러한 디자인 패턴을 Strategy pattern이라 한다.

 

대게 C에 익숙한 사람은 흔히 define 혹은 enum 을 사용하여 상황을 열거한 후 조건문을 통해서 행동을 구분하려 할 것이다.

 

switch( State ){

case State.NORMAL:

behaveNormal();

break;

case State.EMERGENCY:

...

}

 

하지만 이런식의 구현은 상태와 행동이 분리되지 못해 상태에 따른 행동의 수가 늘어날수록 결합도가 높아지고 코드의 확장과 재사용성을 떨어뜨린다. 조금 나아가 행동을 추상화하고 하위 클래스에서 재정의한다 해도 행동의 변화가 클래스 단위로 고정되기 때문에 적절한 처사는 아니다. 만약 상태의 변화와 행동을 분리시킬 수 있다면 결합도 문제와 확장성, 재사용성 문제를 모두 해결할 수 있을것이다.

 

 

위와같이 행동을 구조화하고 공통된 행동을 인터페이스화 하여 상황에 따른 행동의 변화가 상황을 다루는 측에 영향을 미치지 않게한다. 단지 상태가 변하는 순간에 행동전략만 바꿔주면 되는것이다.

 

영화 <Treasure planet>에 보면 주방장 '롱 존 실버'가 자신의 오른쪽 기계팔에 손을 상황에 따라 갈아낀다. 요리를 할때는 칼, 토치, 거품기등이 달린 손을 끼고, 전투를 할때는 총이나 칼이 달린 손을 낀다. Strategy pattern을 설명하는 가장 적절한 예라고 생각한다. 상황이 어떻든 기계손이 사용된다는 행동을 같다. 롱 존 실버의 기계손을 예로들어보자.

public interface ProstheticHand {

public void useFunction1();

public void useFunction2();

}

 

public class CookingProstheticHand implements ProstheticHand {

public void useFunction1(){

// use cooking knife

}

 

public void useFunction2(){

// shake eggs

}

}

 

public class CombatProstheticHand implements ProstheticHand {

public void useFunction1(){

// use pistol

}

 

public void useFunction2(){

// use sword

}

}

 

public class LongJohnSilver {

private ProstheticHand rightProstheticHand;

 

public void doSomething(){

rightProstheticHand.useFunction1();

}

 

public void doTheOtherThing(){

rightProstheticHand.useFunction2();

}

 

public setState(String state){

switch( state ){

case "cooking":

rightProstheticHand = new CookingProstheticHand();

break;

case "combat":

rightProstheticHand = new CombatProstheticHand();

break;

default:

rightProstheticHand = new NormalProstheticHand();

break;

}

}

}

 

실버가 손의 1번기능, 2번기능을 사용한다는데는 어떤 손이든 동일하다. 만약 상황이 바뀌어 손을 바꾼다고 해도 그 순간만 손을 바꿔낄 뿐 행동하는 부분은 전혀 변함이 없다. 다만 위의 예에서, 실버가 요리용 의수를 끼고 전투에 나간다면 난감한 상황에 빠지게되듯 전략적인 패턴을 사용하는 측에서는 바뀌는 전략이 가지는 특성이 무엇인지 정확히 파악하고 있어야 한다는 주의사항이 있다.

 

추가로, Strategy pattern은 State pattern과 많은 부분에서 비교된다. State pattern은 '상태'에 따라 문맥이 변하는 코드에서 문맥속에 상태에 따른 행동을 풀어쓰는것이 아니라 상태를 구조화 하고 상태의 핸들러를 전략적으로 변경하도록 하여 문맥과 상태에 따른 행동의 결합도를 낮추는 패턴이다. 두 패턴의 차이는 서브클래스의 구성을 전략적으로 대체하느냐(Strategy pattern), 상태에 따라 행동할 기능을 전략적으로 정하느냐(State pattern)와 같이 '어떻게' 사용하느냐의 차이에 불과하므로 여기서는 Strategy pattern에 대해서만 정리하려 한다. 기초가 되는 개념은 교체가 필요한 부분을 때내어 상황에 맞게 전략적으로 이용한다는 점에서 동일하다.


 

한줄요약 : 상황에 따라 변경될 수 있는 행동은 따로 때어내어 전략적으로 대처하자

'Coding Note' 카테고리의 다른 글

[Design pattern] Abstract Factory  (0) 2013.01.27
[Design pattern] Observer  (4) 2013.01.22
[ExtJs4] nested model  (0) 2013.01.01
[MFC] MDI에서 child view 접근  (0) 2012.10.17
[MFC] Changing MDI child document's title  (0) 2012.10.08