전략 패턴이라고 부르지만, 사실 상 합성을 강조한 패턴이다.
웹 사이트나 블로그들에서 전략 패턴에 대해서 찾아보면 위와 같은 다이어그램을 제시하고, 아래와 같이 정의하는 것을 보게 된다.
"행위 자체를 클래스화해 동적으로 행위를 자유롭게 바꿀 수 있는 패턴"
그런데 솔직히 무슨 말인지 와닿지 않는다. 심지어 제시한 다이어그램이 DIP 다이어그램 구조와 동일하다.
일단 DIP 개념부터 간단하게 소개하고, 전략패턴과 비교하여 어떤 공통점과 차이점이 있는지 확인해보자.
DIP (Dependency Inversion Principle)
저수준 모듈에서 고수준 모듈이 정의한 추상 타입에 의존하여 역전 관계를 만들어야 한다.
저수준 모듈? 고수준 모듈? 이라는 컨셉이 처음 등장하게 되는데 아래와 같이 예시를 통해 손쉽게 이해할 수 있다.
고수준 모듈 | 저수준 모듈 |
자동차를 만든다. | 자동차 뼈대를 만든다. 운전대를 만든다. 의자를 만든다. 타이어를 만든다. ... |
고수준 모듈이 어떤 단일 기능을 제공하는 모듈이라면 저수준 모듈은 고수준 모듈 기능을 구현하기 위해 필요한 하위 기능들의 실제 구현이다. 그래서 항상 고수준 모듈보다 저수준 모듈의 갯수가 많을 수 밖에 없고, 고수준 모듈에서 저수준 모듈로 흐름이 이동한다. 다시 말해 고수준 모듈 -> 저수준 모듈 의존성을 갖는다는 말이다.
고수준 모듈에서 저수준 모듈로 향하는 흐름은 DIP 에서 이야기하는 저수준 모듈에서 고수준 모듈로 향하는 흐름과 완전히 반대다. 이름에서 역전이라는 말이 나오게 된 이유이다.
"자동차를 만든다" 라는 예제에서 뼈대 객체와 운전대 객체, 의자 객체가 자동차 클래스 내부에 필드로 삽입이 되어 있는데 뼈대는 BMW 클래스로, 운전대는 빨간 휠로, 의자는 가죽의자로 설계했다고 가정하자. 그런데 새로운 요구사항이 등장해서 AUDI 뼈대 객체와 통풍시트 객체도 지원이 필요하다고 한다면 자동차 클래스는 뼈대가 바뀔 때마다, 운전대가 바뀔 때마다, 의자가 바뀔 때마다 새로운 객체들을 가지고 있어야 된다. 이러면 자동차 클래스는 계속해서 수정해야 되니 객체지향의 패러다임 OCP 원칙을 위배하게 된다.
아까 앞에서 살펴보았듯이 고수준 모듈에서 저수준 모듈로 흐름이 향하는데 저수준 모듈의 갯수가 현저히 많아 발생한 문제이다. 갯수를 줄이기 위한 가장 보편적인 방법은 여러 객체들의 공통점을 찾아 저수준 단계를 한 단계 추상화 하는 것이다. BMW 클래스와 AUDI 클래스를 뼈대 클래스로 추상화하여 실체화 관계 또는 상속 관계를 가지게 하면 고수준 모듈은 변경을 하지 않아도 된다. 신기한 건 인터페이스를 주입받기 때문에 고수준에서 저수준으로 가는 흐름은 유지된다.
런타임 시에 인터페이스가 직접 호출되는 게 아닌 구현체인 모듈이 호출되니까 저수준에서 고수준으로 역전시킨 것처럼 보여도 실제 흐름은 고수준에서 저수준으로 간다.
그래서 DIP 다이어그램이 위 그림과 같게 된다.
하지만 주의할 점이 하나 있다. 상속과 실체화 관계는 완벽히 IS-A 관계에 있어야 한다. 여러 모듈들을 합쳐서 추상화한다고 하더라도 틀린 부분이 존재하게 된다. 틀린 부분은 별도의 클래스로 만들어 HAS-A 관계로 만들어야 한다.
이 때 전략 패턴이 등장한다. HAS-A 관계는 합성을 통해 만들 수 있는데 합성은 떼었다 붙였다 할 수 있다.
위 다이어그램과 같이 IS-A 관계에 있지 않는 HAS-A 관계들을 따로 추출하여 합성 구조로 만든 것이 전략패턴이다.
합성을 강조한 디자인 패턴이며, 유연한 구조를 띄기 때문에 자주 사용된다.
'디자인 패턴' 카테고리의 다른 글
[디자인 패턴] 커맨드 패턴 (Command Pattern) (0) | 2022.10.09 |
---|