JUINTINATION
스트래티지(Strategy) 패턴 본문
반응형
스트래티지 패턴이란?
어떤 목적을 달성하기 위해 일을 수행하는 방식, 비즈니스 규칙, 문제를 해결하는 알고리즘 등을 의미하는 전략을 쉽게 바꿀 수 있도록 해주는 패턴이다.
프로그램에서 전략을 실행할 때는 쉽게 전략을 바꿔야 할 필요가 있는 경우가 많이 발생하는데 특히 게임 프로그래밍에서 게임 캐릭터가 자신이 처한 상황에 따라 공격이나 행동하는 방식을 바꾸고 싶을 때 스트래티지 패턴은 매우 유용하게 쓰인다.
다음과 같이 로봇을 만드는 클래스가 있다고 가정해보자.
public class Main {
public static void main(String[] args) {
Robot taekwonV = new TaekwonV("TaekwonV");
Robot atom = new Atom("Ateom");
System.out.println("My name is " + taekwonV.getName());
taekwonV.attack();
taekwonV.move();
}
}
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();
}
class TaekwonV extends Robot {
public TaekwonV(String name) {
super(name);
}
@Override
public void attack() {
System.out.println("Missile attack");
}
@Override
public void move() {
System.out.println("Walking");
}
}
class Atom extends Robot {
public Atom(String name) {
super(name);
}
@Override
public void attack() {
System.out.println("Punch attack");
}
@Override
public void move() {
System.out.println("Flying");
}
}
- 위 코드의 문제점
- 기존 로봇의 공격 또는 이동 방법을 수정하려면 기존 코드를 수정해야 한다.
- 유지 보수의 어려움
- OCP 위반
- 새로운 로봇을 만들어 기존의 공격 또는 이동 방법을 적용하려면 같은 코드를 다시 작성해야 한다.
- 기존 로봇의 공격 또는 이동 방법을 수정하려면 기존 코드를 수정해야 한다.
이를 해결하기 위해 공격과 이동 전략을 다음과 같이 인터페이스로 묶는다.
이를 적용하면 클래스 다이어그램과 코드를 다음과 같이 수정할 수 있을 것이다.
public class Main {
public static void main(String[] args) {
Robot taekwonV = new TaekwonV("TaekwonV");
Robot atom = new Atom("Ateom");
System.out.println("My name is " + taekwonV.getName());
taekwonV.attack();
taekwonV.move();
System.out.println("이동 전략 수정");
taekwonV.setMoveStrategy(new WalkingStrategy());
taekwonV.move();
}
}
interface MoveStrategy {
void move();
}
class FlyingStrategy implements MoveStrategy {
@Override
public void move() {
System.out.println("Flying");
}
}
class WalkingStrategy implements MoveStrategy {
@Override
public void move() {
System.out.println("Walking");
}
}
interface AttackStrategy {
void attack();
}
class PunchStrategy implements AttackStrategy {
@Override
public void attack() {
System.out.println("Punch attack");
}
}
class MissileStrategy implements AttackStrategy {
@Override
public void attack() {
System.out.println("Missile attack");
}
}
abstract class Robot {
private String name;
private MoveStrategy moveStrategy;
private AttackStrategy attackStrategy;
public Robot(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void attack() {
attackStrategy.attack();
}
public void move() {
moveStrategy.move();
}
public void setMoveStrategy(MoveStrategy moveStrategy) {
this.moveStrategy = moveStrategy;
}
public void setAttackStrategy(AttackStrategy attackStrategy) {
this.attackStrategy = attackStrategy;
}
}
class TaekwonV extends Robot {
public TaekwonV(String name) {
super(name);
setMoveStrategy(new FlyingStrategy());
setAttackStrategy(new MissileStrategy());
}
}
class Atom extends Robot {
public Atom(String name) {
super(name);
setMoveStrategy(new WalkingStrategy());
setAttackStrategy(new PunchStrategy());
}
}
또한 전략을 바꿀 때마다 객체를 새로 만들 필요는 없기 때문에 싱글턴 패턴을 적용하면 다음과 같이 코드를 수정할 수 있다.
public class Main {
public static void main(String[] args) {
Robot taekwonV = new TaekwonV("TaekwonV");
Robot atom = new Atom("Ateom");
System.out.println("My name is " + taekwonV.getName());
taekwonV.attack();
taekwonV.move();
System.out.println("이동 전략 수정");
taekwonV.setMoveStrategy(WalkingStrategy.getInstance());
taekwonV.move();
}
}
interface MoveStrategy {
void move();
}
class FlyingStrategy implements MoveStrategy {
private static FlyingStrategy instance = new FlyingStrategy();
private FlyingStrategy() {}
public static FlyingStrategy getInstance() {
return instance;
}
@Override
public void move() {
System.out.println("Flying");
}
}
class WalkingStrategy implements MoveStrategy {
private static WalkingStrategy instance = new WalkingStrategy();
private WalkingStrategy() {}
public static WalkingStrategy getInstance() {
return instance;
}
@Override
public void move() {
System.out.println("Walking");
}
}
interface AttackStrategy {
void attack();
}
class PunchStrategy implements AttackStrategy {
private static PunchStrategy instance = new PunchStrategy();
private PunchStrategy() {}
public static PunchStrategy getInstance() {
return instance;
}
@Override
public void attack() {
System.out.println("Punch attack");
}
}
class MissileStrategy implements AttackStrategy {
private static MissileStrategy instance = new MissileStrategy();
private MissileStrategy() {}
public static MissileStrategy getInstance() {
return instance;
}
@Override
public void attack() {
System.out.println("Missile attack");
}
}
abstract class Robot {
private String name;
private MoveStrategy moveStrategy;
private AttackStrategy attackStrategy;
public Robot(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void attack() {
attackStrategy.attack();
}
public void move() {
moveStrategy.move();
}
public void setMoveStrategy(MoveStrategy moveStrategy) {
this.moveStrategy = moveStrategy;
}
public void setAttackStrategy(AttackStrategy attackStrategy) {
this.attackStrategy = attackStrategy;
}
}
class TaekwonV extends Robot {
public TaekwonV(String name) {
super(name);
setMoveStrategy(FlyingStrategy.getInstance());
setAttackStrategy(MissileStrategy.getInstance());
}
}
class Atom extends Robot {
public Atom(String name) {
super(name);
setMoveStrategy(WalkingStrategy.getInstance());
setAttackStrategy(PunchStrategy.getInstance());
}
}
스트래티지 패턴 컬레보레이션
Strategy : 외부에서 동일한 방식으로 알고리즘을 호출하는 방식을 명시한 인터페이스
ConcreteStrategy : 스트래티지 패턴에서 명시한 알고리즘을 실제로 구현한 클래스
Context : 스트래티지 패턴을 이용하는 역할을 수행하는 클래스, 필요에 따라 동적으로 전략을 바꿀 수 있도록 setter 메서드를 제공
728x90
'JAVA객체지향디자인패턴' 카테고리의 다른 글
커맨드(Command) 패턴 (0) | 2023.07.06 |
---|---|
스테이트(State) 패턴 (0) | 2023.07.06 |
싱글턴(Singleton) 패턴 (0) | 2023.07.05 |
디자인패턴 개요 (0) | 2023.07.03 |
좋은 객체 지향 설계의 5가지 원칙 (SOLID) (0) | 2023.07.02 |
Comments