본문 바로가기
Design Pattern/Behavioral Design

[Design Pattern] (Behavioral) 전략 패턴(Strategy Pattern)

by song.ift 2023. 3. 27.

디자인 패턴 유형

  • Creation Design Pattern
    • 객체의 생성에 관련된 패턴
    • 객체의 생성 로직을 숨김으로써 유연성을 향상시킨다.
  • Strutural Design Pattern
    • 클래스와 객체의 구성에 관련된 패턴
  • Behavioral Design Pattern
    • 객체와 객체 간의 통신에 관련된 패턴

 

[Behavioral Design Pattern] 전략 패턴(Strategy Pattern)

GOF의 디자인 패턴에서 전략 패턴을 다음과 같이 정의하고 있다.

동일 계열의 알고리즘들을 정의하고,
각 알고리즘을 캡슐화하며,
이 알고리즘들을 해당 계열 안에서 상호교체가 가능하도록 만든다.
알고리즘을 사용하는 클라이언트와 상관없이 독립적으로 알고리즘을 다양하게 변경할 수 있게 한다.

하나의 클래스가 많은 행동들을 정의하고, 이런 행동들이 그 클래스의 연산 안에서 복잡한 다중 조건문의 모습을 취할 때, 많은 조건문보다는 행동 각각을 전략(Strategy) 클래스로 만들고, 동적으로 행동의 변경이 필요한 경우 전략(Strategy)을 바꾸어 주는 것으로 알고리즘을 다양하게 변경할 수 있게 해주는 패턴이다.

 

예제

다음의 간단한 예제를 통해 알아보겠다.

 

 

  • AuthProgram : 인증진행을 위한 절차를 구현한다. AuthProgram을 사용하는 쪽에서 필요한 인증방식 객체(AuthStrategy의 구체클래스)를 AuthProgram에 주입해준다.
  • AuthStrategy (추상클래스) : 제공하는 모든 Auth 알고리즘에 대한 공통의 연산들을 정의한다.
  • OAuth, OAuth2, Basic (구체클래스) : AuthStrategy 추상클래스를 각각의 실제 Auth 알고리즘으로 구현한다.

AuthProgram에서는 사용하는 각각의 인증방식(OAuth, OAuth2, Basic)이 내부적으로 어떻게 구현 되어있는지 몰라도 된다.

그저 사용자가 선택한 인증전략(AuthStrategy)의 공통된 사용방법(auth()) 만 알고 있으면 된다.

 

class AuthStrategy {
	auth() {
      throw new Error('auth() must be implement')
    }
}

class OAuth extends AuthStrategy {
    auth() {
      console.log('Authenticating using OAuth Strategy')
    }
}

class Basic extends AuthStrategy {
    auth() {
      console.log('Authenticating using Basic Strategy')
    }
}

class OAuth2 extends AuthStrategy {
    auth() {
      console.log('Authenticating using OAuth2 Strategy')
    }
}

class AuthProgram {
    constructor(authStrategy) {
      this._authStrategy = authStrategy;
    }

    authenticate() {
      if (!this._authStrategy) {
        console.log("No Authentication Strategy set.")
        return
      }
      this._authStrategy.auth()
    }
}

const authProgram = new AuthProgram(new Basic())
authProgram.authenticate()

/* (Console Output)
Authenticating using Basic Strategy
*/

 

 전략패턴의 장점

  • 동일 계열의 관련 알고리즘이 생긴다 : Strategy 클래스 계층은 동일 계열의 알고리즘군을 정의하고, 알고리즘 자체의 재사용도 가능하게 한다.
  • Strategy를 사용하는 Composition클래스에 서브클래싱을 하지 않아도 된다 : 위의 예에서 AuthProgram 클래스에 서브클래싱을 사용하여 Auth 방법을 다르게 처리할 수도 있다. 그러나 이렇게 처리하게 되면 AuthProgram 자체의 행동과 Auth 알고리즘이 혼합되어 유지보수가 어려워진다. 따라서 Auth 알고리즘을 Strategy 클래스로 독립시키면 AuthProgram과 무관하게 알고리즘을 변형시킬 수 있고, 알고리즘을 바꾸거나 확장하기도 쉬워진다.
  • 조건문을 없앨 수 있다 : 서로 다른 행동이 하나로 묶이면 조건문을 사용해서 정확한 행동을 선택해야 한다. 그러나 서로 다른 Strategy 클래스의 행동을 캡슐화하면 이들 조건문을 없앨 수 있다.

전략패턴의 단점

  • Strategy 객체와 Composition클래스 객체 사이에 의사소통 오버헤드가 발생할 수 있다 : 서브클래스에서 구현할 알고리즘의 복잡함과는 상관없이 모든 ConcreteStrategy 클래스는 Strategy 인터페이스를 공유한다. 따라서 어떤 ConcreteStrategy 클래스는 이 인터페이스를 통해 들어온 모든 매개변수를 다 사용하지 않는데도 전달받아야 할 때가 생긴다. 즉, 사용되지도 않을 매개변수를 Composition 객체가 생성하고 초기화하는 경우가 발생할 수 있다.
  • 객체 수가 증가한다 : Strategy들로 생성하는 객체 수가 증가한다.

댓글