Table of Contents
[GoF 디자인 패턴] 전략 (Strategy) 패턴
전략 (Strategy) 패턴
행동(behavioral) 패턴 중 하나로, 동일한 문제를 해결하기 위한 여러 알고리즘이 존재할 때, 이를 캡슐화하고 상호교환이 가능하도록 만들어주는 패턴이다.
알고리즘을 사용하는 로직과 알고리즘을 제공하는 로직을 분리시켜줌으로써, 알고리즘의 변경이나 추가가 필요한 경우 유연하게 변경할 수 있다.
전략 패턴 구성요소
Context 객체가 Strategy 객체를 가지고 있어 Strategy 객체의 변경이나 추가가 용이하다.
- Context : 알고리즘을 사용하는 객체. 적용할 알고리즘을 선택하고 호출
- Strategy : 알고리즘을 캡슐화한 인터페이스
- Concrete Strategy : Strategy 인터페이스를 실제로 구현한 클래스. Context 객체가 필요한 Strategy 을 선택하여 호출.
구현 예제
결제 수단에 따라 다양한 Strategy 를 적용하는 예제를 만들어보았다. 우선 Strategy 인터페이스를 정의한다.
1public interface Strategy {
2 int getPoint(int price);
3}
구체적인 Strategy 클래스(결제 수단)에 따라 적립되는 포인트를 반환하는 메서드인 getPoint() 메서드를 정의한다. 이 Strategy 인터페이스를 구현한 클래스들은 각각 다른 방식으로 알고리즘을 구현할 수 있게 된다.
→ “다양한 Strategy 클래스를 하나의 타입으로 다룰 수 있도록 한다”
Strategy 인터페이스를 구현한 Concrete Strategy 클래스를 만든다.
1public class CardStrategy implements Strategy {
2
3 @Override
4 public int getPoint(int price) {
5 return (int) (price * 0.003);
6 }
7}
8
9public class CashStrategy implements Strategy {
10
11 @Override
12 public int getPoint(int price) {
13 return (int) (price * 0.01);
14 }
15}
Strategy 인터페이스를 구현하는 다양한 Concrete Strategy 클래스를 만들어 고유한 알고리즘을 수행하게 한다. CardStrategy 클래스는 카드 결제를 할 경우, CashStrategy 클래스는 현금 결제를 할 경우에 대한 전략을 수행하게 된다.
→ “클라이언트에서는 인터페이스를 호출하는 것만으로도 해당 인터페이스를 구현한 다양한 전략 클래스를 이용할 수 있게 된다.”
Strategy 클래스를 사용하는 Context 클래스이다.
1public class Payment {
2 private final int price;
3 private final Strategy strategy;
4
5 public Payment(Strategy strategy, int price) {
6 this.strategy = strategy;
7 this.price = price;
8 }
9
10 public void getPoint() {
11 int point = strategy.getPoint(price);
12 System.out.println(point + " 포인트가 적립되었습니다!");
13 }
14
15}
생성자에서는 Strategy 객체와 price 정보를 받아와서 저장하고 getPoint() 메서드를 통해 해당 Strategy 객체와 price 정보에서 계산한 point 값을 반환받을 수 있다.
전략 패턴을 사용하는 클라이언트 코드이다.
1Payment card = new Payment(new CardStrategy(), 10000);
2card.getPoint();
3
4Payment cash = new Payment(new CashStrategy(), 10000);
5cash.getPoint();
6
7Payment phone = new Payment(new PhoneStrategy(), 10000);
8phone.getPoint();
전략 패턴을 사용하여 다양한 결제 방식에 따라 다른 포인트 적립 알고리즘을 적용하도록 구현하였다.
→ “결제 방식이 추가되거나 변경될 때, Payment 클래스를 수정하지 않고도 새로운 전략 객체를 만들어 사용할 수 있기 때문에 유연성과 확장성이 높아진다.”
전략 패턴 고려사항
알고리즘을 동적으로 선택해야 할 때, 비슷한 알고리즘을 가진 다른 클래스들이 존재할 경우에는 전략 패턴을 유용하게 사용할 수 있다. 하지만 알고리즘의 개수가 적거나 자주 변경되지 않는 경우에는 직접 구현하는 것이 더 적합하다.
전략 패턴 사용 시 장점
- 알고리즘을 변경하거나 추가하기 쉽다. - 확장성/유연성 증가
- 캡슐화가 잘 되어 있어 가독성이 좋아지고 유지보수하기 쉬워진다.
- 각각의 Strategy 클래스에 대해 개별적으로 테스트가 가능하다. - 효과적으로 테스트를 수행할 수 있다.
전략 패턴 사용 시 단점
- 구현할 Strategy 클래스가 많아져 코드가 복잡해질 수 있다.
- Strategy 객체를 생성하고 사용하기 위한 오버헤드가 있을 수 있다.