JUINTINATION

스트래티지(Strategy) 패턴 본문

JAVA객체지향디자인패턴

스트래티지(Strategy) 패턴

DEOKJAE KWON 2023. 7. 6. 00:30
반응형

스트래티지 패턴이란?

어떤 목적을 달성하기 위해 일을 수행하는 방식, 비즈니스 규칙, 문제를 해결하는 알고리즘 등을 의미하는 전략을 쉽게 바꿀 수 있도록 해주는 패턴이다.

프로그램에서 전략을 실행할 때는 쉽게 전략을 바꿔야 할 필요가 있는 경우가 많이 발생하는데 특히 게임 프로그래밍에서 게임 캐릭터가 자신이 처한 상황에 따라 공격이나 행동하는 방식을 바꾸고 싶을 때 스트래티지 패턴은 매우 유용하게 쓰인다.

 

다음과 같이 로봇을 만드는 클래스가 있다고 가정해보자.

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