본문 바로가기
CS 지식 공부방/디자인패턴

[헤드퍼스트 디자인패턴 1장] 전략패턴

by Loper Lee 2022. 6. 13.

1장 - 전략패턴

요구사항 : 오리 시뮬레이션 게임 SimUduck

  • 오리 시뮬레이션 게임
    • 이 게임에는 헤엄도 치고 꽥꽤 소리도 내는 다양한 오리가 등장
    • 추후 요구사항이 변경되어 날 수 있는 기능이 추가되어야 함
    • 또 다른 요구사항으로 소리를 내지 못하는 오리라던지, 날지 못하는 오리 등이 추가 됨

문제를 명확하게 파악하기

  • 달라지는 부분을 찾아서 영향을 주이 않도록 캡슐화 한다.
  • 바뀌는 부분과 그렇지 않은 부분 분리하기

해결 방법 1 : 상속(슈퍼클래스)을 통한 해결

  • 클래스 다이어그램

    요구사항이 추가되기 전 클래스 다이어그램

    요구사항 변경으로 인해 추가된 클래스 다이어그램

모든 오리가 꽥꽥 소리를 내고, 헤엄칠 수 있다 생각하여 이런 특성을 모두 슈퍼클래스에서 구현

해당 슈퍼클래스를 상속받은 서브클래스들은 고유한 모양을 나타내는 display메소드를 오버라이딩 해서 자신만의 특성을 만들어 낸다.

장점

  • 단순한 요구사항 변경에 발빠르게 대응이 가능함
  • 코드의 중복이 줄어들음 (코드의 재사용성 증가)

단점

  • 모든 서브클래스가 슈퍼클래스의 메소드를 따르지 않는 예외가 있을 경우 메소드를 오버라이딩 해야만 한다.
  • 슈퍼클래스에 의존하는 서브클래스는 점점더 증가할 것이고, 이후 요구사항이 변동될 시 슈퍼클래스의 수정은 곧 서브클래스의 변동을 의미한다.
    • 즉 한번의 수정이 너무나도 많은 소스에 영향을 미치게 된다.
    • 또한 원치않는 요구사항을 가진 서브클래스의 경우 지속적으로 의미없는 오버라이딩을 하게 된다.

해결 방법 2 : 인터페이스 분리하여 구현

  • 클래스 다이어그램

    인터페이스 분리를 진행한 클래스 다이어그램

공통으로 가지는 행동은 슈퍼클래스로, 부분적으로 가지는 행동은 인터페이스로 분리하여 구현

장점

  • Flyable, Quackable 인터페이스를 통해서 특정한 행동만 구현할 수 있음

단점

  • 같은 행동을 하는 코드가 중복됨
  • 날수있는 오리 중에서도 날아다니는 방식이 서로 다를 수 있는 문제가 있음

해결 방법 3 : 분리된 인터페이스 구현체를 따로 구분

행동을 캡슐화해 구현한 인터페이스와 구현체들

A.K.A. 전략패턴

장점

  • 오리들이 직접 인터페이스를 구현하지 않기 때문에 코드 중복을 걱정할 필요가 없음
  • 새로운 요구사항이 추가되면 인터페이스 구현체를 늘려주면 해결 됨
  • 런타임 도중 동적으로 오리의 행동을 바꿀 수 있음
  • 직정 정의한 메소드를 쓰는것이 아닌 다른 클래스에 행동을 위임함
public abstract class Duck {
    // 직접 구현이 아닌 Setter 혹은 생성자를 통해서 DI 받음
    QuackBehavior quackBehavior;
    ...
    public void performQuack() {
        // 참조 객체에 행동을 위임함
        quackBehavior.quack();
    }
}

정리

  • 상속을 통한 해결은 지속적 요구사항 해결 해결에 어려움을 가진다.
  • 단순히 인터페이스를 분리하여 개별적으로 구현하는것은 코드 중복과 유지보수에 불편함을 가진다.
  • 전략패턴을 사용한다면 행동을 외부로 위임하여 코드 중복 문제를 해결하고, 때에따라 유연하게 행동을 변경할 수 있다.