📌 객체의 행동을 실행 시간에 변경할 수 있도록 해주는 디자인 패턴 중 하나
알고리즘의 일부분을 변경하고 싶을 때 전략 패턴을 사용
간단하게 말해서 객체가 할 수 있는 행위들 각각을 전략으로 만들어 놓고, 동적으로 행위의 수정이 필요한 경우 전략을 바꾸는 것만으로 행위의 수정이 가능하도록 만든 패턴이다.
간단한 예시와 함께 전략 패턴을 사용해보자.
public interface FlyBehavior {
public void fly();
}
public interface QuackBehvior {
public void quack();
}
public abstract class Duck {
FlyBehavior flyBehavior; // interface
QuackBehvior quackBehvior; // interface
public void swim(){
System.out.println("오리가 헤엄친다!")
}
public abstract void display(); // abstract 메서드는 상속받으면 반드시 오버라이딩
public void performQuack(){
quackBehvior.quack();
}
public void performFly(){
flyBehavior.fly();
}
}
FlyBehavior와QuackBehviorinterface를 가지고 있는abstract class Duck을 만들어준다. 매우매우 간단한 구조를 가지고 있다.
FlyBehavior(비행방법)엔 무엇이 있을까? 간단하게 몇 가지만 구현해보자.public class FlyNoWay implements FlyBehavior{
@Override
public void fly() {
System.out.println("날지 못하는 슬픈 짐승이여...");
}
}
저런.. 나는 법을 모르는
FlyBehavior였다... 날 수 있는 오리를 만들기 위해 하늘을 날 수 있는
FlyBehavior를 만들어보자!
public class FlyWithWings implements FlyBehavior{
@Override
public void fly() {
System.out.println("멋진 달이 될래요!");
}
}
날개로 날 수 있는
FlyBehavior를 만들었다! 더 이상 오리는 날 수 없다 엄마에게 혼나지 않는 오리를 만들 수 있을 듯 하다.
QuackBehvior(우는방법)엔 무엇이 있을까? 간단하게 몇 가지만 구현해보자!public class Quack implements QuackBehavior{
@Override
public void quack() {
System.out.println("오리가 꽥꽥 울어요!");
}
}
평범하게 우는 오리를 만들 수 있을 듯 하다.
public class Squeak implements QuackBehavior{
@Override
public void quack() {
System.out.println("장난감 오리에서 꽉꽉 소리가 나요!");
}
}
이번엔 장난감 오리의 울음소리를 만들어 봤다.
public class MuteQuack implements QuackBehavior{
@Override
public void quack() {
System.out.println("소리가 나지 않는다.");
}
}
울지 못하는 오리를 위한
MuteQuack
public class MallardDuck extends Duck{
public MallardDuck() {
quackBehavior = new Quack(); // 평범하게 우는 Behavior
flyBehavior = new FlyWithWings(); // 날개로 하늘을 나는 Behavior
}
@Override
public void display() {
//천둥오리
System.out.println("천둥오리처럼 보인다.");
}
}
public class RubberDuck extends Duck{
public RubberDuck() {
flyBehavior = new FlyNoWay(); // 날 수 없는 Behavior
quackBehavior = new Squeak(); // 장난감 오리의 울음소리 Behavior
}
@Override
public void display() {
System.out.println("고무오리처럼 보인다.");
}
}
public class DecoyDuck extends Duck{
public DecoyDuck() {
quackBehavior = new MuteQuack(); // 울지 못하는 Behavior
flyBehavior = new FlyNoWay(); // 날 수 없는 Behavior
}
@Override
public void display() {
System.out.println("가짜 오리 처럼 보인다.");
}
}
장난감 오리(고무오리), 천둥오리, 가짜 오리를 만들어 보았다!
그런데 대체 어떤 이점이 있길래 이렇게 만드는 걸까?
잠시 간단한 예제를 통해 알아보자.
public class DuckDriver{
public static void main(String[] args) {
List<Duck> duckList = new ArrayList<>();
// Duck 리스트 생성!
duckList.add(new MallardDuck());
duckList.add(new DecoyDuck());
duckList.add(new RubberDuck());
// 천둥오리, 가짜오리, 고무오리 모두 들어가!
duckList.forEach(Duck::display); // -> 메서드 참조
// duckList에 들어있는 오리들, 다들 자기 생김새를 말해봐!
}
}
천둥오리처럼 보인다.
고무오리처럼 보인다.
가짜 오리 처럼 보인다.
매우 신기하게도,
천둥오리.display()나장난감오리.display()와 같이 특정 대상 명령을 하지 않고(Duck::display)로 사용했는데도 불구하고 알아서 차례대로 결과값이 나온다!
public class DuckDriver{
public static void main(String[] args) {
List<Duck> duckList = new ArrayList<>();
// Duck 리스트 생성!
duckList.add(new MallardDuck());
duckList.add(new DecoyDuck());
duckList.add(new RubberDuck());
// 천둥오리, 가짜오리, 고무오리 모두 들어가!
duckList.forEach(Duck::display); // -> 메서드 참조
// duckList에 들어있는 오리들, 다들 자기 생김새를 말해봐!
duckList.forEach(Duck::performQuack);
duckList.forEach(Duck::performFly);
// 물론 우는 방법이나 나는 방법에도 적용된다!
}
}
이처럼 전략 패턴은 객체의 행동을 실행 시간에 변경할 수 있도록 해준다!