본문 바로가기
SW

GoF의 디자인 패턴(Design Patterns: Elements of Reusable Object-Oriented Software) - 5장 행동패턴 :: 전략(Strategy)

by 라꾸스떼(YR) 2020. 5. 12.
반응형

[전략(Strategy) - 객체 행동]

<의도>

동일 계열의 알고리즘군을 정의하고, 각 알고리즘을 캡슐화하며, 이들을 상호교환이 가능하도록 만든다.

<다른 이름>

정책(Policy)

<동기>

알고리즘을 직접 클래스에 하드코딩하는 것은 다음과 같은 이유로 별로 바람직하지 않다.

-줄 분리 코드가 사용자 프로그램에 들어가면 크기도 점점 더 커질 것이고, 유지보수하기도 힘들어진다.

-때에 따라서 필요한 알고리즘이 다르기 때문에 모든 알고리즘을 다 제공할 필요는 없다.

-알고리즘을 구성하는 문장들이 사용자 코드와 합쳐져 있을 때는 새로운 알고리즘을 추가하거나 기존의 것을 다양화하기가 어렵다.

캡슐화된 알고리즘들을 가리켜 전략이라고 한다.

<활용성>

-행동들이 조금씩 다를 뿐 개념적으로 관련된 많은 클래스들이 존재할 때

-알고리즘의 변형이 필요할 때. 기억 공간과 처리 속도 간의 절충에 따라 서로 다른 알고리즘을 정의할 수 있을 것이다.

-사용자가 몰라야 하는 데이터를 사용하는 알고리즘이 있을 때.

-하나의 클래스가 많은 행동을 정의하고, 이런 행동들이 그 클래스의 연산 안에서 복잡한 다중 조건문의 모습을 취할 때.

<구조>

<참여자>

-Strategy:제공하는 모든 알고리즘에 대한 공통의 연산들을 인터페이스로 정의한다.

-ConcreteStrategy:Strategy 인터페이스를 실제 알고리즘으로 구현한다.

-Context:ConcreteStrategy 객첼르 통해 구성된다. Strategy객체에 대한 참조자를 관리하고, 실제로는 Strategy 서브클래스의 인스턴스를 갖고 있음으로써 구체화한다. 또한 Strategy 객체가 자료에 접근해가는 데 필요한 인터페이스를 정의한다.

<협력 방법>

-Strategy 클래스와 Context 클래스는 의사교환을 통해 선택한 알고리즘을 구현한다. Context클래스는 알고리즘에 해당하는 연산이 호출되면, 알고리즘 처리에 필요한 모든 데이터를 Strategy 클래스로 보낸다. 이때, Context 객체 자체를 Strategy 연산에다가 인자로 전송할 수도 있다.

-Context 클래스는 사용자 쪽에서 온 요청을 각 전략 객체로 전달한다. 사용자는 필요한 알고리즘에 해당하는 ConcreteStrategy 객체를 생성하여 이를 Context 클래스에 전송한다.

<결과>

1.동일 계열의 관련 알고리즘군이 생긴다. 상속을 통해서 알고리즘 공통의 기능성들을 추출하고 이를 재사용할 수 있다.

2.서브클래싱을 사용하지 않는 대안이다. 알고리즘을 Strategy 클래스로 독립시키면 Context와 무관하게 알고리즘을 변형시킬 수 있고, 알고리즘을 바꾸거나 이해하거나 확장하기도 쉽다.

3.조건문을 없앨 수 있다. 많은 조건문을 포함하는 코드는 전략 패턴의 필요성을 생각하게 한다.

4.구현의 선택이 가능하다. 동일한 행동에 대해서 서로 다른 구현을 제공할 수 있다.

5.사용자(프로그램)는 서로 다른 전략을 알아야 한다. 사용자는 각 구현 내용을 모두 알아야 한다. 사용자가 이렇게 서로 다른 행동 각각의 특징을 이미 알고 있을 때 전략 패턴을 사용한다.

6.Strategy 객체와 Context 객체 사이에 의사소통 오버헤드가 있다.

7.객체 수가 증가한다.

<구현>

1.Strategy 및 Context 인터페이스를 정의한다. 한 가지 방법은 Context가 Strategy의 연산 쪽으로 데이터를 매개변수에 담아 보내도록 하는 것이다. 이렇게 하면 Strategy 클래스와 Context 클래스 간의 결합도를 낮출 수 있다. 다른 방법은 Context 객체가 자기 자신을 Strategy 객체에 인자로 보내고, Strategy 객체는 Context 객체에서 데이터를 요청하는 것이다.

2.전략을 템플릿 매개변수로 사용한다. C++의 템플릿 기능을 사용함으로써 전략을 가진 클래스를 구성할 수 있다. 이 기법은 두가지 조건이 만족되어야 한다. (1)Strategy 객체를 컴파일 타임에 결정할 수 있을 때, (2) Strategy 객체가 런타임에 바꿀 필요가 없을 때이다.

템플릿을 이용하면, Strategy 인터페이스를 정의하는 추상 클래스를 정의할 필요가 없어진다.

3.Strategy 객체에 선택성을 부여한다.

<예제 코드>

Strategy 클래스와 Context 클래스에 어떤 인터페이스를 정의하는지가 얼마나 이 패턴의 의도대로 설계하였느냐를 판가름한다.

<잘 알려진 사용예>

<관련 패턴>

전략 객체는 규모가 작은 클래스들이므로 플라이급 패턴으로 정의하는 것이 좋다.

반응형

댓글