전략 패턴(Strategy Patturn) — 헤드 퍼스트 디자인
전략패턴은 알고리즘 군을 정의하고 캡슐화해서 각각의 알고리즘 군을 수정해서 쓸 수 있게 해줍니다. 전략 패턴을 사용하면 클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있습니다.
우리가 다양한 종류의 오리 클래스들을 만들 때 중복되는 함수와 변수들을 모아 하나의 슈퍼 클래스를 만든 다음 그 클래스를 확장해서 다른 종류의 오리들을 만들 수 있다.
하지만 이 경우 새로운 종류의 오리를 만들 때 문제가 생길 수 있다.
MarllardDuck의 경우 하늘을 날 수 있고 소리를 낼 수 있기 때문에 quack() 함수와 fly() 함수를 그대로 사용할 수 있다.
반면에 RubberDuck의 경우 소리는 낼 수 있지만 하늘은 날 수 없기 때문에 fly() 함수의 기능이 없거나 사용할 수 없어야 한다.
class RubberDuck extends Duck {
@Override
void quack() {
System.out.println("하늘을 날 수 없습니다.");
}
}
그럼에도 하늘을 날 지 못하는 오리들이 많아진다면 모든 quack() 함수들을 재정의한다는 단점이 생긴다.
헤드 퍼스트 디자인 패턴에서는 바뀌는 부분과 그렇지 않은 부분을 분리하는 방법으로 해결한다.
위의 예처럼 앞으로 추가할 오리들은 모두 같은 소리를 낸다. 하지만 날 수 없는 오리가 존재할 수도 있다고 생각한다면 quack() 함수는 바뀌지 않는 부분이고 fly() 바뀌는 부분이라고 생각할 수 있다.
이렇게 변하는 부분은 Duck 클래스에서 구현하지 않고 다른 클래스에 위임한다.
class Duck {
FlyBehavior flyBehavior;
void quack() {
System.out.println("꽥");
}
void performFly() {
flyBehavior.fly();
}
}
interface FlyBehavior {
void fly();
}
class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("하늘을 날다");
}
}
class FlyNoWays implements FlyBehavior {
@Override
public void fly() {
System.out.println("하늘을 날 수 없습니다.");
}
}
class RubberDuck extends Duck {
public RubberDuck() {
flyBehavior = new FlyNoWays();
}
}
public static void main(String[] args) {
RubberDuck rubberDuck = new RubberDuck();
rubberDuck.performFly(); // 하늘을 날 수 없습니다.
rubberDuck.quack(); // 꽥
}
애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분을 분리한다.
구현보다는 인터페이스에 맞춰서 프로그래밍한다.
상속보다는 구성을 활용한다.