전략 패턴(Strategy Pattern)은 알고리즘군을 정의하고 각각을 캡슐화하여 교체 가능하게 만든다. 이는 클라이언트가 알고리즘을 선택할 수 있게 하고, 선택한 알고리즘을 변경하지 않고도 다양한 알고리즘을 적용할 수 있도록 한다.
여기서 '전략'이란 일종의 알고리즘이 될 수 도 있으며, 기능이나 동작이 될 수도 있는 특정한 목표를 수행하기 위한 행동 계획을 말한다.
즉, 어떤 일을 수행하는 알고리즘이 여러가지 일때, 동작들을 미리 전략으로 정의함으로써 손쉽게 전략을 교체할 수 있는, 알고리즘 변형이 빈번하게 필요한 경우에 적합한 패턴이다.
내비게이션 앱 앱은 사용자가 어떤 도시에서든 빠르게 자신의 위치를 파악할 수 있는 아름다운 지도를 중심으로 구성되었 있다.
앱에서 가장 많이 요청된 기능 중 하나는 자동 경로 계획이다. 사용자는 주소를 입력하고 해당 목적지까지의 최단 경로를 지도에 표시할 수 있어야 한다.
새로운 라우팅 알고리즘을 추가할 때마다 내비게이터의 주요 클래스 크기가 두 배로 불어났다. 어느 순간, 이 거대한 클래스는 유지보수하기가 너무 어려워졌다.
전략 패턴을 통해 특정한 작업을 여러 가지 다른 방법으로 수행하는 클래스를 가져와서, 이러한 알고리즘을 전부 전략이라고 불리는 별도의 클래스로 추출하는 것을 제안한다.
전략 패턴은 세 가지 구성 요소로 이루어진다.
각각 다른 전략 구현체(Road, PublicTransport, Walking)를 통해 원하는 전략으로 변경할 수 있다.
public interface WeaponStrategy {
public abstract void runStrategy();
}
public class StrategyGun implements WeaponStrategy {
@Override
public void attack() {
System.out.println("Use Gun");
}
}
public class StrategySword implements WeaponStrategy {
@Override
public void attack() {
System.out.println("Use Sword");
}
}
public class StrategyBow implements WeaponStrategy {
@Override
public void attack() {
System.out.println("Use Bow");
}
}
// Context
public class Soldier {
void runContext(WeaponStrategy waepon){
System.out.println("Fight");
waepon.attack();
System.out.println("Stop");
}
}
// Client
public class Client {
public static void main(String[] args) {
Soldier ramdo = new Soldier();
ramdo.runContext(new StrategyGun());
ramdo.runContext(new StrategySword());
ramdo.runContext(new StrategyBow());
}
}
같은 문제의 해결책으로 상속을 이용하는 템플릿 메서드 패턴과 객체 주입을 통한 전략 패턴 중에 선택/적용할 수 있다.
단일 상속만이 가능한 자바 언어에서는 상속이라는 제한이 있는 템플릿 메서드 패턴보다는 전략 패턴이 더 많이 활용된다.
클라이언트가 전략을 생성하여 전략을 실행할 컨텍스트에 주입하는 패턴이다.