White Whale Studio

Strategy Pattern (전략 패턴) 본문

IT Engineering/객체지향&디자인 패턴

Strategy Pattern (전략 패턴)

glorymind 2016. 6. 14. 14:45
반응형

전략 패턴의 중점

- 알고리즘을 추상화 -> 전략(Strategy) 

- 알고리즘을 사용하는 책임을 가지고 있는 콘텍스트(Context)에서 알고리즘(전략)을 분리하는 설계방법

- 흐름 : Client가 전략을 고른다.(어떤 전략을 쓸까나~) → 선택된 전략을 Dependency Injection으로 Context에 넘겨준다.

          → Context는 전달받은 전략으로 초기화하여 필요한 자원(프로퍼티, 메서드 등)을 사용한다.


전략 패턴을 사용해서 콘텍스트 코드의 변경없이 새로운 전략을 추가, 수정이 용이하다는 점이다.

필요한 전략을 직접 선택해서 Context에 넘겨주기 때문에 Context에서는 전략과 관련된 부분에서는 코드를 수정하는 수고를 하지 않아도 되는 것이다.

주로 if-else를 사용하면서도 비스무리한 경우 전략패턴을 사용한다.

위의 그림에서 보는 바와 같이 전략들로부터 공통되는 부분은 Interface로 구성하여 이 인터페이스를 상속받는 콘크리트 클래스(A, B)들을 각각 구현한다.

구현한 콘크리트 클래스들을 콘텍스트에서 사용하는데 이 때 전략을 직접 선택하는 것이 아니라 콘텍스트의 클라이언트가 콘텍스트에서 사용할 전략을 전달해 준다.

즉, Dependency Injection(의존 주입)을 통해서 전략을 전달해준다.

Client가 필요에 따라서 전략을 선택하고 Interface를 상속받은 콘크리트 클래스는 Interface의 인스턴스로 치환이 가능하므로 

동적으로 전략을 콘텍스트에 전달할수 있게된다.

코드 상으로 한번 살펴보면 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface IDiscountStrategy
    {
        int getDiscountPrice(Item item);
    }
 
    public class FirstGuestDiscountStrategy : IDiscountStrategy
    {
 
        public int getDiscountPrice(Item item)
        {
            return Convert.ToInt16(item.getPrice() * 0.9);
        }
    }
 
    public class NonFreshItemDiscountStrategy : IDiscountStrategy
    {
 
        public int getDiscountPrice(Item item)
        {
            return Convert.ToInt16(item.getPrice() * 0.8);
        }
    }
cs

우선 인터페이스와 콘크리트 클래스의 모습을 참고하면 된다.

위의 IDiscountStrategy 인터페이스를 구성하고 이 인터페이스를 상속받아 콘크리트 클래스로써 FirstGuestDiscountStrategy와 NonFreshItemDiscountStrategy를 구현한다.

이제 컨텍스트에서 이 구현된 콘크리트 클래스를 불러와서 써야되는데 코드는 다음과 같다.


1
2
3
4
5
6
7
8
9
10
        // 전략 구현
        private IDiscountStrategy ids;
        private void ClientToContext()
        {
            Calculator cl = new Calculator(ids);
            ids = new FirstGuestDiscountStrategy();            
            //ids = new NonFreshItemDiscountStrategy();            
 
            cl.calculate(item);
        }

cs


위에서 보는 것처럼 IDiscountStrategy 인터페이스를 상속받은 2개의 콘크리트 클래스는 IDiscountStrategy의 인스턴스로,

치환이 가능하므로 필요에 따라서 전략을 IDiscountStrategy의 인스턴스로 초기화하고 해당하는 함수를 불러 사용하는 형태인 것이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        // 전락구현방법
        private IDiscountStrategy discountStrategy;
 
        public Calculator(IDiscountStrategy ds) // 초기화 과정에서 DI로 할인 전략을 지정
        {
            this.discountStrategy = ds;
        }
 
        public int calculate(List<Item> items)
        {
            int sum = 0;
            foreach (Item item in items)
            {
                sum += discountStrategy.getDiscountPrice(item);
            }
 
            return sum;
        }

cs


위의 코드는 Calculator 즉, 여기서는 콘텍스트 역할의 클래스의 코드이다.

초기화 과정에서 DI로 전략을 지정하고 추후에 calculate 메서드를 호출하여 사용한다.



자 이제 윈폼으로 한번 앞에서 구현한 내용을 실행해보자.

기본적인 화면 구성은 위와 같다.

첫 손님 할인 버튼과 비신선 할인 버튼을 클릭하면


1
2
3
4
5
6
7
8
9
10
11
12
        private void btn_firstGuest_Click(object sender, EventArgs e)
        {
            te_results.Text = "첫 고객 할인 10% \r\n";
 
            ids = new FirstGuestDiscountStrategy(); // Dependency Injection   
        }
 
        private void btn_nonFresh_Click(object sender, EventArgs e)
        {
            te_results.Text = "비 신선 할인 20% \r\n";
            ids = new NonFreshItemDiscountStrategy();            
        }
cs

위의 코드에서와 같이 ids (위의 ClientToContext() 부분 참조)에는 필요에 따른 전략(콘크리트 클래스)가 결정되고, "계산" 버튼을 클릭하게 되면


1
2
3
4
5
6
7
8
9
10
11
        private void btn_calculate_Click(object sender, EventArgs e)
        {            
            Calculator cl = new Calculator(ids);
 
            foreach (Item item in items)
            {
                te_results.Text += item.itemName + " : " + cl.CalculateItem(item) + "원" + Environment.NewLine;
            }
            
            te_results.Text += string.Format("Total : {0} 원", cl.CalculateItems(items).ToString());
        }
cs

위와 같이 ids에 적용된 전략을 가지고 Dependency Injection로 Calculator에 전달된다.

전달된 Calculator를 통해서 기존에 선택된 할인 전략으로 할인율을 계산하여 반환한다.


결과 화면을 보면 다음과 같다.









※ 본 포스팅은 참고용입니다. 다른 여타 개념적인 부분들을 읽고 스스로 이해하여 작성한 것으로 개념적으로 잘못된 부분이 있을 수도 있습니다.

기타 의견이나 잘못된 부분이 있는 경우 알려주시면 감사하겠습니다~^^


반응형
Comments