전략 패턴은 실행 중에 알고리즘을 선택할 수 있게 하는 행위 소프트웨어 디자인 패턴이다.
- 특정한 계열의 알고리즘들을 정의하고
- 각 알고리즘을 캡슐화하며
- 이 알고리즘들을 해당 계열 안에서 상호 교체가 가능하게 만든다.
전략은 알고리즘을 사용하는 클라이언트와는 독립적으로 다양하게 만든다.
위와 같이 상황에 따라 다양한 알고리즘을 필요로 하는 경우 전략 패턴을 사용할 수 있다.
바로 인터페이스와 해당 인터페이스를 구현한 클래스를 사용하는 것
인터페이스를 통해 전략을 추상화 시켜놓은 후, 적재 적소에 필요한 전략을 구현한 Class를 삽입
public interface ShuffleStrategy {
List<Card> shuffle(final List<Card> cards);
}
public class RandomShuffleStrategy implements ShuffleStrategy {
@Override
public List<Card> shuffle(final List<Card> cards) {
Collections.shuffle(cards);
return cards;
}
}
위에서 언급했던 것 처럼, ShuffleStrategy라는 인터페이스를 만들어 Shuffle 이라는 전략을 추상화 시킨 예시이다.
이제 전략 콘크리트 클래스에 각자 의도에 맞는 Shuffle 전략을 작성한다.
RandomShuffleStrategy라는 클래스가 전략 콘크리트 클래스의 예시로,
코드를 보면 매개변수로 넘겨받은 카드를 랜덤으로 섞어 반환하는 것을 볼 수 있어요.
public static CardDeck make(final ShuffleStrategy shuffleStrategy) {
final List<Card> shuffledCard = shuffleStrategy.shuffle(cards);
return new CardDeck(shuffledCard);
}
전략을 사용하는 프로그램의 흐름으로, 서로 다른 전략에 따른 코드의 변경이 필요 없다.
해당 context에서는 넘겨 받은 전략 콘크리트의 shuffle 메서드를 통해 cards를 섞는다.
ShuffleStrategy를 구현한 클래스는 shuffle 이라는 전략을 가지고 있다는 것을 보장하기 때문에,
cards를 섞는 일은 전략 콘크리트 객체에게 위임할 수 있다 !!!
만일 전략 패턴이 아닌 다른 방식으로 구현했다면
필요한 전략에 맞추어 행동하기 위해 if - else 등의 분기문으로 구구절절..
과도한 if - else 문은 곧 메서드/객체가 여러 책임을 가진다는 것이므로 지양하자
public void run() {
final CardDeck cardDeck = CardDeckFactory.make(new RandomShuffleStrategy());
}
여기서 전략 사용자에게 구체적인 전략 콘크리트 클래스를 주입 !
현재 코드에서는 바로 RandomShuffleStrategy의 객체를 생성하여 주입시켜줬지만,
사용자의 요청에 따라 다른 전략을 사용해야 하는 경우,
매번 다른 전략을 사용해 객체를 생성해야 하는 경우 등에서 전략 패턴은 빛을 발한다.