전략 패턴?
말이 어렵다. 개발 쪽 용어들 중 대부분은 이렇게 이름만 들었을 때는 너무 추상적이다 싶은 개념들이 많은 것 같다. (아무래도 개발 커뮤니티가 영어권 나라를 중심으로 발전해왔고, 이걸 번역하는 영어가 되는 개발자 분들이 이런 언어들을 직역하면서 생긴 현상이 아닐까 추측해본다...)
아무튼 전략 패턴은 interface와 깊게 연관되어있다.
그런데 이제까지 내가 사용해본 interface는 주로 어떤 interface를 구현한 클래스들은 1. 움직이기 2. 말하기 3. 정지 이런 기능들을 구현해야해! 와 같은 용도로 사용되었다.
즉 구체적인 구현 코드는 구현 클래스 나름대로 정의하되, 적어도 이런 이런 기능들은 갖추고 있어야돼! 라는 의미로 사용되었다.
public interface Robot {
void move();
void speak();
void stop();
}
public class RobotA implements Robot {
@Override
public void move() {
// 보폭 10cm로 이동
}
@Override
public void speak() {
// 영어를 사용
}
}
public class RobotB implements Robot {
@Override
public void move() {
// 보폭 10cm로 이동
}
@Override
public void speak() {
// 한국어를 사용
}
}
가만보자.. 서로 다른 로봇이긴 한데... 같은 기능을 다른 방식으로 구현하는 경우도 있고, 다른 방식으로 구현하는 경우도 있다..
이대로라면 기능이 확장될 때마다 코드가 수정되어야하는데..
어떻게 하면 좀 더 OCP(Open Closed Principle)을 지킬 수 있을까?
그런데 전략 패턴에서는 interface를 조금 다른 방식으로 사용한다.
즉 어떤 general한 기능들을 갖춘 클래스에 초점을 맞추기보다는, 해당 기능 하나를 구현체 클래스로 만드는 개념이다. 이렇게 되면, 위의 상황에서 구현 클래스들이 가지는 기능의 재활용성이 좋아지고, 이 기능들을 수정해야하는 상황에서 매번 모든 구현 클래스를 수정할 필요가 없어진다.
즉, 기능 하나가 구현 클래스로 정의되고, 이 기능들을 가진 객체는 DI 방식으로 이 기능들을 주입받기만 하면 된다.
말로 하니 복잡한데.. 아래의 예제 코드로 살펴보자
public interface MoveStrategy {
void move();
}
public class Walk implements MoveStrategy {
@Override
public void move() {
// 보폭 10cm로 이동
}
}
public interface SpeakStrategy {
void speak();
}
public class SpeakEnglish implements SpeakStrategy {
@Overrid
public void speak() {
// 영어를 사용
}
}
public class SpeakKorean implements SpeakStrategy {
@Overrid
public void speak() {
// 한국어를 사용
}
}
public class Robot {
private final MoveStrategy moveStrategy;
private final SpeakStrategy speakStrategy;
public Robot (MoveStrategy moveStrategy, SpeakStrategy speakStrategy) {
this.moveStrategy = moveStrategy;
this.speakStrategy = speakStrategy;
}
public void move() {
moveStrategy.move();
}
public void speak() {
speakStrategy.speak();
}
}
public class RobotApplication {
public static void main(String[] args) {
Robot robotA = new Robot(new Walk(), new SpeakEnglish());
Robot robotB = new Robot(new Walk(), new SpeakKorean());
robotA.speak(); // 영어로 말한다
robotB.speak(); // 한국어로 말한다
}
}