CastleJo의 개발일지

Strategy

|

개요

행위 패턴 중 하나로 매우 유명한 패턴이다.
행위를 캡슐화 하여 동적으로 행위을 자유롭게 바꿀 수 있는 패턴이다. 즉 전략을 쉽게 바꿀 수 있는 패턴이다. 예를들어 어떤 게임 캐릭터의 무기에 따라 행동 모션을 바꾸고싶을때 매우 유용하다.

또한 상속이 아닌 집약관계를 사용한다.

집약관계란?

  • 참조값을 인자로 받아 필드를 세팅하는 경우
  • 전체 객체의 라이프타임과 부분 객체의 라이프 타임은 독립적이다.
  • 즉 전체 객체가 사라진다고 해도 부분 객체는 사라지지 않는다.

사례

예를들어 로봇을 만든다고 해보자.

public abstract class Robot {
  private String name;
  public Robot(String name) { this.name = name; }
  public String getName() { return name; }
  // 추상 메서드
  public abstract void attack();
  public abstract void move();
}

public class TaekwonV extends Robot {
  public TaekwonV(String name) { super(name); }
  public void attack() { System.out.println("I have Missile."); }
  public void move() { System.out.println("I can only walk."); }
}
public class Atom extends Robot {
  public Atom(String name) { super(name); }
  public void attack() { System.out.println("I have strong punch."); }
  public void move() { System.out.println("I can fly."); }
}

public class Client {
  public static void main(String[] args) {
    Robot taekwonV = new TaekwonV("TaekwonV");
    Robot atom = new Atom("Atom");

    System.out.println("My name is " + taekwonV.getName());
    taekwonV.move();
    taekwonV.attack();

    System.out.println()
    System.out.println("My name is " + atom.getName());
    atom.move();
    atom.attack();
  }
}
// 출처 : https://gmlwjd9405.github.io/2018/07/06/strategy-pattern.html

만약 아톰이 걷게만 하고싶으면? 태권브이를 날게 하고싶으면?
기존 클래스를 수정해야한다. 이는 OCP에 위배된다.
또한 move() 메서드가 중복이된다.
만약 걷는 방식에 문제가 있으면, 또 따로 설정해야한다.

해결책

이를 해결하기 위해서는, Strategy 패턴을 이용한다.

인터페이스를 만들고 이를 변수로 가지며 set() 함수로 옵션을 정한다.

public abstract class Robot {
private String name;
private AttackStrategy attackStrategy;
private MovingStrategy movingStrategy;

public Robot(String name) { this.name = name; }
public String getName() { return name; }
public void attack() { attackStrategy.attack(); }
public void move() { movingStrategy.move(); }

// 집약 관계, 전체 객체가 메모리에서 사라진다 해도 부분 객체는 사라지지 않는다.
// setter 메서드
public void setAttackStrategy(AttackStrategy attackStrategy) {
  this.attackStrategy = attackStrategy; }
public void setMovingStrategy(MovingStrategy movingStrategy) {
  this.movingStrategy = movingStrategy; }
}

public class TaekwonV extends Robot {
public TaekwonV(String name) { super(name); }
}
public class Atom extends Robot {
public Atom(String name) { super(name); }
}

// 인터페이스
interface AttackStrategy { public void attack(); }
// 구체적인 클래스
public class MissileStrategy implements AttackStrategy {
  public void attack() { System.out.println("I have Missile."); }
}
public class PunchStrategy implements AttackStrategy {
  public void attack() { System.out.println("I have strong punch."); }
}
// 인터페이스
interface MovingStrategy { public void move(); }
// 구체적인 클래스
public class FlyingStrategy implements MovingStrategy {
  public void move() { System.out.println("I can fly."); }
}
public class WalkingStrategy implements MovingStrategy {
  public void move() { System.out.println("I can only walk."); }
}

public class Client {
public static void main(String[] args) {
  Robot taekwonV = new TaekwonV("TaekwonV");
  Robot atom = new Atom("Atom");

  /* 수정된 부분: 전략 변경 방법 */
  taekwonV.setMovingStrategy(new WalkingStrategy());
  taekwonV.setAttackStrategy(new MissileStrategy());
  atom.setMovingStrategy(new FlyingStrategy());
  atom.setAttackStrategy(new PunchStrategy());

  /* 아래부터는 동일 */
  System.out.println("My name is " + taekwonV.getName());
  taekwonV.move();
  taekwonV.attack();

  System.out.println()
  System.out.println("My name is " + atom.getName());
  atom.move();
  atom.attack();
}
}
// 출처 : https://gmlwjd9405.github.io/2018/07/06/strategy-pattern.html