티스토리 뷰

스트트래티지 패턴은 알고리즘 군을 정의하고 각각을 캡슐화여 교환하고 재사용할 수 있도록 만드는 전략이다. 스트래티지 패턴을 활용하면 클라이언트와는 

독립적으로 알고리즘을 변경할 수 있다. 이 내용만 봐서는 다소 이해하기 힘들 수 있다. 아래 다이어그램을 보자!



현재 Duck 클래스가 있고, Duck 클래스를 상속받는 MallardDuck, RedheadDuck 두 클래스가 존재한다. 두 클래스는 Duck 의 특성과 동일하기 때문에 상속을 통해

구현이 되어 있다. 상속을 사용했기 때문에 상위 클래스의 메소드를 그대로 사용할 수 있어, 코드의 중복성 제거 및 코드의 재사용을 기대할 수 있다.

그러나 만약에 아래 다이어그램과 같이 고무오리에 해당하는 RubberDuck 클래스가 새로 추가가 된다면, 어떻게 될까?



RubberDuck 클래스는 기존 클래스와 달리 quack() 메소드가 다르기 때문에 quack() 메소드를 오버라이드 해야하고, 날 수도 없기 때문에 fly() 메소드를 호출 할 때

아무 행동도 하는 메소드로 오버라이드 해야 한다. 이와 같은 클래스가 계속 생긴다면 상속의 장점을 활용할 수 없다. 

그래서 상속이 아닌 인터페이스를 사용해보자!



인터페이스를 활용한다면, RubberDuck 클래스는 Quckable 인터페이스만 구현하면되고, 날지 않기 때문에 Flayable 인터페이스는 구현하지 않아도 된다.

그러나 인터페이스를 활용한다면, 모든 클래스들이 추상메소드를 오버라이드 해야 하기 때문에 코드의 재사용과 중복성 제거를 기대할 수 없다.

만약에, fly() 메소드의 동작하는 방식을 변경한다고 하면, fly() 메소드를 오버라이드하는 모든 클래스에 대해서 수정을 해야한다. 

그렇다면 코드의 유지보수 및 관리에도 문제가 될 수 있다. 이 설계에서 계속 변하기 때문에 문제가 되는 부분은 어디일까? 

그 부분을 따로 뽑아내서 캡슐화하여 변하지 않는 부분들과 분리시킨다면, 변화가 또 발생했을 때 분리시킨 부분만 수정하면 되지 않을까?

그렇다면 기존의 변하지 않는 소스코드에는 영향을 미치지 않을 수 있지 않을까? 

 - 변하는 부분 : fly(), quack()

 - 변하지 않는 부분 : display(), swim()

스트래티지 패턴에서 가장 중요한 것은, 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리시키는 것이다!



스트래티지 패턴을 활용해서 계속 변화하는 부분을 캡슐화하였다. 이처럼 구현한다면, 상속과 인터페이스를 했을 때의 단점은 보완되고 장점만 사용할 수 있다.

각각의 클래스는 인터페이스 형식의 인스턴스 변수를 갖게 된다. 인터페이스 형식이기 때문에 인터페이스를 구현하고 있는 모든 구현객체를 가질 수 있다.

그 뜻은, FlyBehavior 인터페이스 형식의 변수는 다형성을 이용해서 FlyWithWing, FlyNoWing 구현 객체를 모두 가질 수 있고, 이 구현객체를 통해 fly() 메소드를

사용할 수 있다. 결국은 RubberDuck 객체에 setter 메소드를 통해 FlyBehavior 변수만 바꾼다면, 언제든지 날 수 있고, 언제든지 날지 않을 수 도 있다. 

구현 클래스가 아닌 인터페이스에 맞추어 설계를 했기 때문에 다형성을 활용할 수 있고, 확장도 할 수 있게 되었다. 

스트래티지 패턴은 상속보다는 구성을 활용한다. 구성을 이용하면 시스템을 유연하게 설계할 수 있다. 


정리하자면, 스트래티지 패턴 2가지 전략만 기억하자!

 1. 변화하는 부분과 변화하지 않는 부분을 나누고, 변화하는 부분은 별도로 캡슐화 한다.

 2. 상속보다는 구성을 활용하여, 코드의 유연성을 확보하자!

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함