본문 바로가기

💻 개발IT/Design Patterns

3. Behavior 패턴 - Strategy Pattern

문제 정의

1) 모든 오리는 꽥 2) 모든 오리는 같은 방향으로 수영 3) 서로 display 방식이 다름 요구사항이 존재할 때, 보통 아래와 같이 공통 부분을 abstruct class Duck에 만들고 고유한 Implementation이 필요한 부분은 subclass에 설계한다.

 

 

그러나, 요구사항에 오리가 날 수 있는 behavior를 추가해달라는 요청이 생겨 아래와 같이 Duck에 추가를 하면

날지 않아야하는 일반 오리와 다른 러버덕도 같이 날게 된다.

 

그럼 러버덕의 quack() 함수처럼 fly()도 override하여 아무 것도 안 하게 해야하나?

근데 러버덕같은 변종 class가 계속해서 증가한다면?

 

그럼 interface로 해결해본다면,

필수적이지 않은 함수는 interface(Flyable, Quackable)로 분리하여 필요한 곳에서만 호출하도록 설계한다.

 

하지만 이 경우,

 1) 코드 재사용 불가 (중복 코드 증가) - 각 class에서 코드 구현

 2) 유지보수 어려움

 문제가 있다.

 

상속의 재사용은 이점을 주지만, 

coupling이 강하게 되어서 SW를 flexible하게 만드는 것을 막게 된다.

 

 

Stratege Pattern

모든 class가 사용하고 변하지 않은 것(swim, display...)과 optional한 것을 분리시켜 optional 부분(변하게 되는 것. ex. fly, quack)을 encapsulate하라!

 

특징

 

*  Program to an interface, not an implementation

  • super type에 대해서 프로그래밍하라 (하위 타입이 생성, 변경되어도 영향 크지 않음)
  • exploit Polymorphism (상속 뿐만 아니라 composition 관계(더 선호)로도 가능)

    ※ OO에서 재사용 방법

    1. 상속 : subclass의 implementation이 parent class의 implementation 기반하여 생성된다. (white-box reuse) 
    • 장점 : 컴파일 time에 이루어지고 사용하기 편리
    • 단점 : subclass가 parent class에 상당히 종속적이게 되고 런타임에 변경 불가능

      2. Object Composition : Interface 통해서만 소통 (black-box reuse)
      • 장점 : implementation이 런타임에서 대체 가능하여 dependency 감소
      • 단점 : 이해 어려움

 

예시) Programming to an implementation

예시) Programming to an interface/supertype

혹은 concrete한 class명까지 없앨 수 있다.

 

 

 

 

해결 방법

1. 각 behavior을 표현할 수 있는 class들을 각각 생성

     이와 같이 하면 변종이 증가하면 behavior가 계속 추가되지만 다른 곳에 영향을 미치지 않게 된다.

2. 해당 class들을 모두 포용할 수 있는 상위 Interface 생성

 

 

Duck class는 아래와 같이 만들어서 polymorphic하게 함수 호출하면 된다.

 

코드 예시)

 

더 나아가서 아래처럼 attribute의 setter을 만들어주면,

손쉽게 런타임에 바꿔줄 수 있다.

 

전체 설계 디자인

 

 

Stratege  Pattern을 사용한 Sorting Example

 

반응형