전략 패턴

2018, May 15    

디자인 원칙

  • 달라지는 부분을 찾아 내고, 달라지지 않는 부분으로 부터 분리 시킨다.
  • 상속보다는 구성을 활용한다.
  • 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.


전략(Strategy) 패턴

알고리즘을 정의 하고 각각을 캡슐화하여 교체해서 사용할 수 있도록 만든다.
스트래티지를 활용하면 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경 할 수 있다.

‘오리’를 주문 제작하는 회사에서 아래와 같은 구조로 클래스를 디자인 하였다.
이 회사에 주로 들어오는 오리 생산 주문에 나는 방식(fly)과 소리내는 방식(quack)에 다양한 주문이 들어오고 있다고 해보자.

fly메소드와 quack메소드를 오버라이드 해서 새로운 서브 클래스를 만들어 내면 되겠지만,
만약 날수 있는 기능이 필요 없는 오리에 대한 주문이 들어온다면?
날 필요가 없는 RedheadDuck의 경우는 필요도 없는 메소드를 상위 객체로 부터 물려(?)받고 굳이 아무것도 하지 않는 것으로 오버라이드 해야 한다.

변화하는 부분(fly, quack)을 분리해보면 어떨까?
fly, quack을 인터페이스로 추상화 하고 각기 다른 특성들을 구현체로 생성하였다.
이렇게 ‘날다’와 ‘소리내다’의 알고리즘을 따로 떼어 새로운 객체로 분리하는 것을 캡슐화라고 한다.

Duck 추상화 클래스에 새로 만든 인터페이스 타입의 변수를 선언하고, ‘fly’, ‘quack’메소드를 수정하였다.

이렇게 상속보다 구성을 활용했을때의 장점이 무엇일까?
만약 MallardDuck을 주문하던 client가 높이 나는 기능이 아닌 낮게 나는 오리로 변경해 달라고 주문을 변경했다고 해보자.
MallardDuck의 생성자에서 flyBehavior에 날지 못하게 하는 클래스의 생성자, 즉 FlyNoWay의 인스턴스를 할당해주면 된다.
또한 다른 오리에게도 다양한 성질의 나는 방식의 알고리즘을 줄수 있어 코드의 반복을 피할 수 있다.
높이 날면서 날개가 아닌 프로펠라를 이용해 나는 오리 주문이 들어온다면? 역시 Flaytable을 구현하는 새로운 구현체를 만들어서 끼어서 쓰면 된다.

<< 정리 >>

이처럼 스트래티지 패턴은 알고리즘군을 정의하고 각각을 캡슐화하여 바꿔 쓸 수 있게 만든다.
스트래티지 패턴을 이용하면 알고리즘을 활용하는 클라이언트와 독립적으로 알고리즘을 변경할 수 있다.