본문 바로가기
Programming/OOP

[Design Pattern] Strategy Pattern, 전략 패턴

by TinKerBellBass 2022. 4. 18.
728x90
반응형

헤드퍼스트 디자인 패턴 개정판이 출판되었다. 안 살 이유는 없지.

바로 사서 다시 처음부터 읽어보고 있는데, 이번에는 블로그에 정리를 좀 해볼까 한다.

 

확장(extends) 과 구성(composition)

상속이라는 말을 좋아하지 않아서 확장이라고 했다.

추상화된 객체를 조금 더 구체적인 객체로 확장해 나가는 것이 확장이다.

예를 들어 '마법사' 객체를 확장해서 '불 마법사', '물 마법사' 등의 객체를 만들 수 있고,

'불 마법사' 객체를 확장해서 '공격형 불 마법사', '방어형 불 마법사' 등의 객체를 만들 수 있다.

'마법사'보다는 '불 마법사'가 더 구체적이고, '불 마법사'보다는 '공격형 불 마법사'가 더 구체적이다.

 

구성은 의존관계를 맺는 것이라고 생각하면 된다.

예를 들어 '자동차'라는 객체가 있으면

이 자동차를 구성하기 위해서는 '바퀴', '엔진' 등이 필요한데.

'바퀴', '엔진'이 바뀌면 다른 '자동차'가 된다.

즉 '자동차'는 '바퀴', '엔진'에 의존하고 있다.

 

Strategy Pattern

전략 패턴? 스타크래프트가 생각나는 이름이다.

전략과 전술, 전쟁광들이 좋아할만한 단어인데 난 평화주의자라서 그런지 썩 마음에 들지는 않는다.

'알고리즘 캡슐화 패턴'이라고 이름지었으면 어땠을까.

 

전략 패턴은 다양한 패턴의 행동을 캡슐화 해서 필요한 행동을 구성을 통해 가져다 쓰는 패턴이다.

책의 예를 빌리면 오리는 날 수 있고, 꽥꽥 울 수 있다.

난다는 행동과 운다는 행동은 오리마다 다양할 것이다.

날개로 난다, 로켓으로 난다 등의 다양한 패턴의 난다는 행동을 하나로 묶어서 패키지화하고

인터페이스를 통해 사용할 수 있게 캡슐화하여 하나의 알고리즘 군처럼 만드는 것이 전략 패턴의 핵심이다.

 

이렇게 캡슐화된 난다는 행동은 사용하는 쪽에서 객체를 생성할 때

의존성 주입을 통해 사용할 수도 있고, 세터를 통해 행동을 변경할 수도 있다.

한번 정해진 행동이 바뀌어서는 안 될 불변의 경우는 생성자 주입을 사용하고,

변경해야 할 필요성이 있을 때는 세터를 정의해 주면 된다.

 

Strategy Pattern Class Diagram

책의 예제를 그대로 코딩하는 것은 저작권 문제도 있을 것이고,

생각 없는 개발자로 생각될 수 있기 때문에 머리를 굴려

Go, Java, Kotlin, Typescript 로 구현해 보았다.

요즘 Go 만 쓰다 보니 자꾸 다른 언어들이 기억에서 멀어져서 

간단히 손 푼다는 생각으로 그나마 아는 거 다 해보았다.

클래스 다이어그램은 자바 기준으로 그렸다.

전략 패턴의 핵심이 되는 수수료 알고리즘 군은 Fee 인터페이스와 Fee 인터페이스를 구현하고 있는 두 클래스이고,

Fee 인터페이스의 calculate 메서드를 통해 수수료를 계산할 수 있다.

수수료 알고리즘 군을 사용하는 곳은 송금 서비스이다.

 

송금 서비스인 Remit 은 추상 클래스로

calculateFee 메서드는 생성자 주입받은 Fee 구현체의 calculate 메서드를 통해 수수료를 구하고,

calculateAmount 메서드는 위에서 구한 수수료와 송금액을 합해 총송금액을 구하고 있다.

Remit 추상 클래스를 확장한 두 클래스는 Fee 인터페이스 구현체 중 필요한 것을 생성자 주입받아 사용하며,

수수료 계산은 Remit 추상클래스를 통해 구한다.

 

Go, Java, Kotlin, Typescript 로 구현한 소스는  git subtree 를 사용한 다음 리포지토리에서 볼 수 있다.

https://github.com/Jongwon-Hyun/design_pattern

 

 

 

 

728x90
반응형

댓글