본문 바로가기

취업과 기본기 튼튼/빽 투더 기본기

[디자인 패턴 10편] 행동 패턴, 스트레티지(Strategy)

1. 개념

스트레티지 패턴은 행동/전략 등 동일계열의 알고리즘들을 인터페이스-캡슐화하고,
알고리즘들을 컴포지션(위임 형태로) 가지는 패턴이다.

1.1. 구조

출처 : https://www.researchgate.net/

  • Context
    • 클라이언트가 직접 사용하는 클래스
    • Strategy 인터페이스를 위임하고(has) 하고 있음.
  • Strategy
    • 구체적인 알고리즘들의 공통 스펙을 정의하는 클래스
  • ConcreteStrategy
    • 구체적인 알고리즘들을 구현하는 클래스

1.2. 장점

  • 상황에 따라 사용할 알고리즘을 쉽게 바꿀 수 있다.
  • 알고리즘 구현부와 사용부가 분리되어 있다.
    • 인터페이스로 사용자는 일관성있게 알고리즘을 가져다 쓸 수 있고,
    • 각 알고리즘들은 동일한 인터페이스를 가지되, 각각 목적에 따라 구현은 다르게할 수 있다.

1.3. 단점

  • 다 사용하지 않는 정보들을 모든 알고리즘이 떠안아야 한다.
    • 각 구체적인 알고리즘들마다 필요한 입력 파라미터가 다 다를 수 있다.
    • 하지만 인터페이스로 파라미터가 고정되어 있으므로, 굳이 이 알고리즘에 필요없는 파라미터도 다 받게된다.
  • 알고리즘 수 만큼 전체 객체 수가 증가한다.

1.4. 활용 상황

  • 상황에 따라 사용해야할 알고리즘(전략)을 클라이언트가 정해야 할 때.
  • 동일 계열의 알고리즘들을 인터페이스로 통일하여 제공해야 할 때.

2. 구현

클라이언트는 Context 객체를 사용한다고 가정하자.
Context 내 필요한 알고리즘들을 다음과 같이 사용할 수 있다.

if __name__ == "__main__":
  context = Context(ConcreteStrategyA())
  context.do_some_business_logic()

  context = Context(ConcreteStrategyB())
  context.do_some_business_logic()

Context 는 다음과 같이 정의되어 있음.

class Context():

  def __init__(self, strategy: Strategy) -> None:
    self._strategy = strategy

  def do_some_business_logic(self) -> None:
    result = self._strategy.do_algorithm(["a", "b", "c", "d", "e"])

동일계열 알고리즘들의 인터페이스 정의

class Strategy(ABC):

  @abstractmethod
  def do_algorithm(self, data: List):
    pass

위 인터페이스를 따르는 각 알고리즘 구현체 정의

class ConcreteStrategyA(Strategy):
  def do_algorithm(self, data: List) -> List:
    return sorted(data)


class ConcreteStrategyB(Strategy):
  def do_algorithm(self, data: List) -> List:
    return reversed(sorted(data))

3. 참고