[헤드퍼스트 디자인패턴] 1. 전략 패턴
전략 패턴 (Strategy Pattern, 객체 지향 패턴)
전략 패턴은 알고리즘 그룹을 정의하고 각 그룹을 별도 클래스로 캡슐화해서 각 그룹마다 서로 다른 알고리즘 객체로 변경할 수 있도록 도와주는 디자인 패턴입니다. 클라이언트에서 사용되는 알고리즘을 별도 클래스로 분리해 클라이언트에게 영향을 미치지 않고 독립적으로 변경할 수 있다는 장점이 있습니다.
객체 지향 디자인 원칙
책에 따르면 다음의 원칙에 따라 전략 패턴을 적용했을 때 보다 객체 지향적인 코드를 작성할 수 있습니다.
1. 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분과 분리한다.
코드에서 수시로 바뀔 수 있는 부분은 따로 다른 클래스로 뽑아서 캡슐화합니다.
바뀔 수 있는 부분을 분리하면, 바뀌지 않는 부분에 영향을 미치지 않고도 그 부분만 수정하거나 또는 확장할 수 있습니다.
2. 구현보다는 인터페이스에 맞춰서 프로그래밍 한다.
여기서 말하는 인터페이스는 중의적인 의미를 가집니다.
의미 1. 자바의 구조( = Java의 Interface)
의미 2. 상위 형식에 맞춰 프로그래밍하는 행동( = 인터페이스, 추상 클래스, 부모 클래스)
달라지는 부분에 대한 책임은 클라이언트가 아닌 다른 클래스에 위임하도록 합니다.
그리고 기존 클래스에서 달라지는 부분에 대한 클래스 변수를 선언할 때, 어떤 구현 클래스도 넣을 수 있도록 추상 클래스, 인터페이스와 같은 상위 형식으로 선언해 사용하도록 합니다.
3. 상속보다는 구성을 활용한다.
- 상속: "A는 B이다."
- 구성(Composition): "A에는 B가 있다."
객체지향의 특징에 '상속'이 있기는 하지만, 상속에는 장점만큼 단점도 많답니다 :)..
상속으로 클래스를 분리하면 사용하지 않는 부모 클래스의 메소드도 모두 오버라이딩해 구현해야 한다는 귀찮음이 있습니다.
그래스 가급적이면 달라지는 부분에 대한 별도 클래스를 생성할 때에는 구성을 활용하도록 합니다.
전략 패턴의 구조
1. Context: 우리가 전략 패턴을 적용할 기존 코드
- 전략의 상위 클래스 변수를 선언하면 사용할 전략 구현 클래스를 손쉽게 변경하거나 확장할 수 있습니다.
2. Strategy: 하나의 행동을 의미하는 전략 인터페이스
- Context는 Strategy 인터페이스의 메소드를 호출해 행동을 수행할 수 있습니다.
- Strategy 인터페이스를 상속하여 구체적인 행동을 정의할 수 있습니다
3. ConcreteStrategy: Strategy 인터페이스를 상속해 실제 구체적인 알고리즘을 구현한 클래스
- ex) MoveStrategy 인터페이스를 상속해 RunStrategy, WalkStrategy, FlyStrategy 등의 클래스를 구현할 수 있습니다.
예시)
꽥꽥 소리를 내는 오리의 추상 클래스 Duck
public abstract class Duck {
// 꽥꽥 소리를 내는 행동은 어떤 오리냐에 따라 달라질 수 있어 다른 클래스로 분리
QuackBehavior quackBehavior;
public void performQuack() {
quackBehavior.quack();
}
}
꽥꽥 소리를 내는 행동에 대한 인터페이스 QuackBehavior
public interface QuackBehavior {
public void quack();
}
꽥꽥 소리를 내는 행동 인터페이스 QuackBehavior의 구현 클래스
public class PlainQuack implements QuackBehavior {
public void quack() {
System.out.println("꽥");
}
}
public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("조-용");
}
}
public class SQuack implements QuackBehavior {
public void quack() {
System.out.println("삑");
}
}
Duck의 구현 클래스
public class MallardDuck extends Duck {
public MallardDuck() {
// "꽥" 소리를 내는 행동 구현 클래스 주입
quackBehavior = new PlainQuack();
// "조-용" 소리를 내는 행동 구현 클래스 주입
// quackBehavior = new MuteQuack();
// "삑" 소리를 내는 행동 구현 클래스 주입
// quackBehavior = new SQuack();
}
public void display() {
System.out.println("저는 물오리입니다.");
}
}
참조:
헤드 퍼스트 디자인 패턴(개정판)
유지관리가 편리한 객체지향 소프트웨어 만들기! “『헤드 퍼스트 디자인 패턴(개정판)』 한 권이면 충분합니다!”
m.hanbit.co.kr