블링블링 범블링

전략 패턴(Strategy Pattern) 본문

Technology/객체 지향 디자인 패턴

전략 패턴(Strategy Pattern)

뻠스키 2018. 4. 18. 10:25

전략패턴(Strategy Pattern)


전략패턴이란 동적을 알고리즘을 교체할 수 있는 구조를 말한다. 알고리즘 인터페이스를 정의하고, 각각의 알고리즘 클래스별로 캡슐화하여 각각의 알고리즘을 교체 사용 가능하게 한다. 


즉, 하나의 결과를 만드는 목적(메소드)는 동일하나, 그 목적을 달성할 수 있는 방법(전략, 알고리즘)이 여러가지 존재할 경우에 사용하는 패턴이다. 보통 기본이 되는 템플릿 메서드(Template Method Pattern)과 함께 가장 많이 사용되는 패턴 중에 하나다. 


아래 그림은 전략패턴을 적용한 클래스다이어그램이다. Context의 변경을 최소화하고, 인터페이스를 통해 다양한 타입을 만들어 코드를 변경할 수 있다. 이해를 돕기 위해서 예시를 들어 전략패턴을 적용해보자. 




급여를 계산하는 프로그램이 있다고 생각해보자. 급여를 받는 사람의 직급에 따라서 받는 급여금액이 달라진다. 직급이 사원, 대리, 팀장이 있다고 가정했을 때 아래의 코드로 보여줄 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Calculator {
     
    public int calculate(String rank,int money) {
         
        if(rank=="사원") {
            return (int) (money + money*(0.1))  ;
        }
        else if(rank =="대리") {
            return (int) (money + money*(0.2)) ;
        }
        else {//팀장
            return (int) (money + money*(0.3)) ;
        }
    }
 
}


만약 직급이 더 다양하게 늘어나면 어떻게 될까? 더 늘어난 직급만큼 조건문을 추가해서 급여를 다르게 줘야하는 상황이 발생할 것이다. 그리고 만약 실적에 따라서 보너스를 급여에 추가로 지급하는 경우가 생겨나면 어떻게 고쳐야할까? 새로운 전략이 추가될 때마다 조건문이 늘어나고, 결국은 많은 조건이 생겨날 수록 코드가 복잡해져서 수정하기가 어려워질 것이다.


아래코드는 전략패턴을 적용한 코드다.

[Calculator Class]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Calculator {
     
    private payMoney payStrategy;
     
    public Calculator(payMoney payStrategy) {
        this.payStrategy = payStrategy;
    }
     
    public int calculate(String rank,int money) {
         
        return payStrategy.getMoney(money);
    }
 
}

[payMoney Interface]

1
2
3
public interface payMoney {
    public int getMoney(int money);
}
[Clerk Class]
1
2
3
4
5
6
7
8
public class Clerk implements payMoney {
 
 
    public int getMoney(int money) {
        return (int) (money +money*(0.1));
    }
     
}
[AssistantManager Class]
1
2
3
4
5
6
7
8
9
public class AssistantManager implements payMoney {
 
 
    public int getMoney(int money) {
        return (int) (money +money*(0.2));
 
    }
 
}
[Manager Class]
1
2
3
4
5
6
7
8
public class Manager implements payMoney{
     
     
    public int getMoney(int money) {
        return (int) (money +money*(0.3));
 
    }
}


아래 클래스 다이어그램으로 보면 클래스는 이렇게 구성되어 있다.



문제에서 직급에 따라 다른 급여를 부여하지만 공통적인 점은 급여를 지급한다는 목적을 가지고 있다. 따라서 급여를 지급하는 것을 하나로 묶어서 표현하고 다른 전략(직급, 성과)에 따라서 추상화를 구현해주면 된다.

 

그림에서 [payMoney Interface]는 급여계산을 추상화했다. [Calculator Class]는  급여계산 알고리즘을 제공하면서 급여계산의 책임을 가지고 있다. 여기서 급여 계산 방법을 추상화하고 있는 [payMoney Interface]를 전략이라고 부르고 급여계산의 기능의 자체의 책임을 갖고있는 [Calculator Class]는 Context라고 부른다. 이렇게 특정 Context에서 알고리즘 전략을 별도로 분리하는 설계방법이 전략패턴이다.


전략패턴에서는 Context는 사용할 전략을 직접 선택하지 않지만 Context의 클라이언트가 Context에 사용할 전략을 전달해준다. 즉, 의존주입을 이용해서 Context에 전략을 전달해준다. 그리고 전략이 어떤 메서드를 제공할 지의 여부는 Context가 전략을 어떤식으로 사용하느냐에 따라서 달라진다.


전략패턴을 이용하면 Context의 코드의 변경없이도 새로운 전략을 추가할 수 있다는 점이 있다. 만약 실적에 따라 급여를 다르게 줘야하는 경우 Context의 변경없이 전략을 하나 추가하면 된다.  [payMoney Interface]에 plusgetMoney()를 추가하는 방법을 생각할 수 있다. 

이러한 점을 볼 때 전략패턴은 개방폐쇄원칙이 잘 지켜졌다는 점을 알 수 있다. 확장이 용이하고, 변경에는 닫혀있는 구조이기 때문이다. Context 클래스의 구현과 알고리즘의 구현을 서로 독립적으로 분리시켜주기 때문에 이해하기 쉽고, 유지보수와 동적으로 알고리즘이 변경이 가능하다.

하지만 클라이언트와 Strategy의 하위 클래스들은 데이터의 참조를 위해서 연관관계를 가질 수 밖에 없는데 이는 결합도를 커지게 한다. 그리고 전략패턴은 실행시간에 사용되는 객체 수를 증가시키는 단점이 있어 객체의 수를 줄여주기 위해 Singleton패턴이나 Flyweight패턴을 활용하게 된다.




참조 위키디피아 전략패턴

출처 : http://meylady.tistory.com/

Comments