# 전략 (Strategy) 패턴
# 전략패턴이란 무엇인가요?
개념
여러 알고리즘을 캡슐화 하고 상호 교환 가능하게 만드는 패턴.
- 객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고,
- 유사한 행위들을 캡슐화하는 인터페이스를 정의하여,
- 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써
- 행위를 유연하게 확장하는 방법.
- Context : 원래의 로직을 수행하던 클래스
- ConcreteStrategy : 각각의 알고리즘들이 구현된 클래스
- Strategy : 추상화된 알고리즘 수행 인터페이스
# 전략 패턴을 언제 사용해야할까요?
상황가정
'무궁화꽃이 피었습니다'를 하는 코드가 있다고 하자. "무궁화 꽃이~"까지는 파란 불. "피었습니다!"까지는 빨간 불이다.
해당 클래스는 speed를 가지는데, speed마다 "무궁화꽃이" 혹은 "피었습니다"를 말하는 속도가 다르다. (speed가 높을 수록 빠름)
public class BlueLightRedLight {
private int speed;
public BlueLightRedLight(int speed) {
this.speed = speed;
}
public void blueLight() {
if (speed == 1) {
System.out.println("무 궁 화 꽃 이");
} else if (speed == 2) {
System.out.println("무궁화꽃이");
} else {
System.out.println("무광꼬치");
}
}
public void redLight() {
if (speed == 1) {
System.out.println("피 었 습 니 다.");
} else if (speed == 2) {
System.out.println("피었습니다.");
} else {
System.out.println("피어씀다");
}
}
}
public class Client {
public static void main(String[] args) {
BlueLightRedLight blueLightRedLight = new BlueLightRedLight(3);
blueLightRedLight.blueLight();
blueLightRedLight.redLight();
}
}
그렇다면
만약에 여기서 스피드가 추가된다면 어떻게 될까??
직접 blueLight()
, redLight()
내부를 수정해야 하므로, SOLID의 원칙 중 OCP( Open-Closed Principle )에 위배된다.
# 전략패턴을 적용해보자
public interface Speed {
void blueLight();
void redLight();
}
- 먼저 Strategy인터페이스를 정의한다.
public class Fastest implements Speed {
@Override
public void blueLight() {
System.out.println("무광꼬치");
}
@Override
public void redLight() {
System.out.println("피어씀다.");
}
}
public class Faster implements Speed {
@Override
public void blueLight() {
System.out.println("무궁화꽃이");
}
@Override
public void redLight() {
System.out.println("피었습니다.");
}
}
public class Normal implements Speed {
@Override
public void blueLight() {
System.out.println("무 궁 화 꽃 이");
}
@Override
public void redLight() {
System.out.println("피 었 습 니 다.");
}
}
- 각각의 ConcreteStrategy인 Slower(speed가 1), Normal(speed가 2), Faster(speed가 3)를 구현한다.
public class BlueLightRedLight {
public void blueLight(Speed speed) {
speed.blueLight();
}
public void redLight(Speed speed) {
speed.redLight();
}
}
- 원래의 Context에서 실행할 때, 단순히 해당 전략에 대한 메소드만 수행하도록 한다. 간단!!
import java.util.Collections;
import java.util.Comparator;
public class Client {
public static void main(String[] args) {
BlueLightRedLight game = new BlueLightRedLight();
game.blueLight(new Normal()); // 무 궁 화 꽃 이
game.redLight(new Fastest()); // 피어씀다.
}
}
- 사용측에서는 전략을 지정하여 바로 사용할 수 있다.
# 전략 패턴의 장단점은 무엇일까?
장점
- 새로운 전략을 추가하더라도 기존 코드를 변경하지 않는다.
- 상속 대신 위임을 사용할 수 있다.
- 런타임에 전략을 변경할 수 있다.
단점
- 복잡도가 증가한다.
- 클라이언트 코드가 구체적인 전략을 알아야 한다
# 전략 패턴의 예시는 무엇일까?
- 자바의 Comparator
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class JavaSample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(5);
System.out.println(numbers); // 10 5
Collections.sort(numbers, Comparator.naturalOrder());
System.out.println(numbers); // 5 10
}
}
- Spring의 ApplicationContext
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringSample {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext();
ApplicationContext applicationContext1 = new FileSystemXmlApplicationContext();
ApplicationContext applicationContext2 = new AnnotationConfigApplicationContext();
}
}
# 출처
- https://victorydntmd.tistory.com/292
- https://kingchan223.tistory.com/324