소프트웨어 개발자/디자인패턴

[디자인패턴] 행동 패턴 - 전략(Strategy) 패턴

yubi5050 2024. 5. 4. 15:54

행동(Behavioal) 패턴

객체들이나 클래스들 사이에 상호 작용이나 책임(역할)분배를 하는 방법에 대한 패턴. 여러 객체에 책임을 분배하고, 객체 간의 종속도 최소화 한다. 

 

주요 패턴으론 다음 사항들이 있다.

  • 옵저버(Observer) 
  • 커맨드(Command)
  • 상태(State) 
  • 전략(Strategy) <- 이번 글에서 다룰 내용
  • 책임 연쇄(Chain_Of_Responsibility)
  • 반복자(Iterator)
  • 중재자(Mediator)
  • 반복자(Visitor)

 

전략 (Strategy) 패턴이란

행동 패턴 방법 중 하나로 동일한 레벨의 다양한 알고리즘을 정의 및 캡슐화 하고, 런타임시 동적으로 해당 알고리즘을 선택할 수 있게 하는 디자인 패턴이다. 

이로서, 복잡한 알고리즘 내용을 비즈니스 로직에서 분리 하여 감출 수 있고, 클라이언트는 런타임 중 자유롭게 알고리즘을 수행하고 변경 할 수 있다.

= 바꿔 쓸 수 있는 행동을 캡슐화하고, 어떤 행동을 사용할지는 서브클래스에 위임한다.

 

등장 배경

 

예시로

  • 여행자들이 목적지 까지 가기 위한, 다양한 방법(대중교통, 차량 등등)에 대해 네비게이션을 통해 볼 수 있다고 가정
  • 여행자들은 원하는 방법을 선택할 때 마다, 해당 방법으로 목적지 까지 가는 방법을 보여 줄 수 있다. 

 

예시 구조

1. 목적지 까지 가기 위한 전략(알고리즘, Strategy) 들은 다 캡슐화를 한다.

  • ex. RouteStrategy 인터페이스를 상속 받은 RoadStrategy, PublicTransport Strategy, Walking Strategy
  • buildRoute(): 캡슐화된 알고리즘 전략을 선택하는 하나의 메소드 

 

2. Navigator 는 만들어진 전략 객체 중 하나를 선택한다. 

  • RouteStrategy 를 참조(객체 변수로 가지며)하며, 내부 함수를 통해 전략을 업데이트 한다. 

 

https://refactoring.guru/images/patterns/diagrams/strategy/solution-2x.png

 

예시 상세 구조

위 '예시 구조' 단락과 개념은 동일하다.(좀더 일반화)

 

1. Context

  • Context 객체 에서는 캡슐화 된 전략 (알고리즘, Strategy)을 참조 하고 있다.
  • setStrategy() 메소드를 통해 전략을 변경 가능하다.

 

2. Strategy

  • Strategy 인터페이스와 구현한 ConcreteStrategies 객체가 존재한다.
  • 기본적으로 알고리즘을 수행하는 execute() 함수를 가진다.

 

3. Client

  • 전략(Strategy) 객체를 생성한다.
  • Context의 setStrategy() 함수에 생성한 전략 객체를 인자로 준다.
  • 차후 다른 전략을 선택시 전략 객체를 생성 -> setStrategy() 함수를 자유롭게 수행한다.

 

https://refactoring.guru/images/patterns/diagrams/strategy/structure-2x.png

 

장단점

장점

  • OCP. 새로운 전략을 기존 코드 수정 없이 사용할 수 있다.
  • 런타임에 알고리즘을 변경할 수 있다.
  • 주된 비즈니스 로직 코드와 알고리즘 구현을 분리할 수 있다.

 

단점

  • 런타임간 전략 변경이 잦지 않고, 선택할 수 있는 알고리즘(전략) 도 많지 않다면, 이 패턴을 이용한 오버엔지니어링할 필요 없다.
  • 함수나 클래스로 분리하는 것 말고도 익명 함수(함수형 지원) 같은 방법 정도 로도 가볍게 처리하는 것도 좋다.

 

다른 패턴과의 관계 

with. 브릿지(Bridge), 상태(State), 전략(Strategy), 어댑터(Adapter)

  • 다른 객체에게 할 일을 위임한다는 점에서 공통점을 가진다. 

 

 

vs 커맨드(Command)

  • 객체와 액션들을 파라미터화하여 사용하기 때문에 비슷하지만, 목적에서 차이가 날 수 있다. 
  • 커맨드는 요청을 요청 정보를 가지고 있는 독립 실행 객체로 전환하는 과정에서, 요청 실행을 지연 위해 큐에 넣어 실행을 미루거나, 커맨드의 기록에 저장하여 되돌리기 기능 등을 위해 사용 한다.
  • 전략은 같은 레벨의 다른 방법으로 변경하기 위한 사용

 

 

vs 데코레이터 (Decorator)

  • 데코레이터는 객체의 겉을 바꾸지만(확장), 전략은 속을 바꾼다.

 

 

vs 템플릿 메서드 (TemplateMethod)

  • 템플릿 메소드는 상속(inheritance)에 기반하여, 서브클래싱(자식클래스)을 통한 확장으로 알고리즘을 변경할 수 있게 한다.
  • 전략은 구성(Composition)에 기반하여, 다른 전략을 제공하여 알고리즘을 변경한다. (병렬형)
  • 템플릿 메서드는 class level이고 정적이다.
  • 전략은 객체 레벨이고 런타임이다.

 

 

vs 상태 (State)

  • 상태 패턴은 전략 패턴의 확장으로 여겨질 수 있다. (유사하다)
  • 두 전략 모두 구성(Compostion)에 기반하여, 원하는 객체(컨텍스트)의 행동을 변경한다.
  • 전략(Strategy)은 이 객체들이 모두 독립적이고, 서로를 모른다.
  • 상태(State)는 상태 구현체들 간의 독립성을 강제하지 않고, 의지에 따라 컨텍스트의 상태도 변경 할 수 있다.