티스토리 뷰

디자인 패턴

TIL(17) - 전략 패턴(Strategy)

나죽나강 2021. 6. 3. 18:10

# 전략 패턴

"클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴"

전략 패턴은 객체의 꽃이라고도 불린다. 전략 패턴은 템플릿 메서드 패턴과 유사하다. 차이점이 있다면 템플릿 메서드 패턴은 상속을 이용하여 문제를 해결하지만 전략 패턴은 객체 주입을 통해 문제를 해결한다.

 

# 전략 패턴 적용X

Q. 전략 패턴을 적용하지 않은 예시를 어떻게 들어야 할까요? (언제 어떤 코드에서 전략 패턴을 사용해야 하는지에 대해 알고 싶습니다.)

public interface Strategy {
    public abstract void runStrategy();
}

public class StrategyGun implements Strategy{
    @Override
    public void runStrategy() {
        System.out.println("탕탕탕(연발)");
    }
}

public class StrategySword implements Strategy {
    @Override
    public void runStrategy() {
        System.out.println("챙챙챙");
    }
}

public class StrategyBow implements Strategy{
    @Override
    public void runStrategy() {
        System.out.println("슝슝슝");
    }
}

public class Soldier {
    public static void main(String[] args){
        StrategyGun strategyGun = new StrategyGun();
        StrategySword strategySword = new StrategySword();
        StrategyBow strategyBow = new StrategyBow();

        strategyGun.runStrategy();
        strategySword.runStrategy();
        strategyBow.runStrategy();
    }
}

전략 패턴은 개방 폐쇄 원칙(OCP)와 의존 역전 원칙(DIP)과 관련이 많이 있습니다. 객체지향에 대해 공부하였다면 위 방식의 코드는 문제가 많다는 것을 알 수 있습니다. 위 코드에서 현재 연발로 총을 "탕탕탕" 쏘고 있습니다. 하지만 저는 갑자기 단발로 "탕" 쏘고 싶어 StrategyGun클래스의 runStrategy( ) 메소드를 "탕(연발)"로 수정하게 되면 OCP원칙과 DIP원칙을 위배하게 됩니다.  < 설명 방향이 이상하다 / 전략 패턴과는 연관이 없는 설명인거 같음...! (책 내용 아님!)

 

전략 패턴이 적용되지 않은 사례를 설명하고 싶어서 제가 생각해 본 것입니다.

 

# 전략 패턴 코드 (스프링 책 코드)

public interface Strategy {
    public abstract void runStrategy();
}

public class StrategyGun implements Strategy{
    @Override
    public void runStrategy() {
        System.out.println("탕탕탕(연발)");
    }
}

public class StrategySword implements Strategy {
    @Override
    public void runStrategy() {
        System.out.println("챙챙챙");
    }
}

public class StrategyBow implements Strategy{
    @Override
    public void runStrategy() {
        System.out.println("슝슝슝");
    }
}

public class Soldier {
    void runContext(Strategy strategy){
        strategy.runStrategy();
    }
}

public class Client {
    public static void main(String[] args){
        Strategy strategy = null;
        Soldier rambo = new Soldier();

        strategy = new StrategyGun();
        rambo.runContext(strategy);

        strategy = new StrategySword();
        rambo.runContext(strategy);

        strategy = new StrategyBow();
        rambo.runContext(strategy);
    }
}

즉, 전략 패턴을 사용하게 된다면 총, 검, 활  이외에 미사일, 탱크가 추가 되어도 코드의 변경없이 원하는 기능의 객체를 생성하여 주입해 주면 된다는 장점이 있습니다. 

 

 

 

# 우테코 전략 패턴

전략 패턴은 동일 계열의 알고리즘들을 정의하고 각 알고리즘을 캡슐화하여 알고리즘들을 상호 교체가 가능하게 만든다.  전략 패턴은 객체 주입을 통해 문제를 해결합니다.

public interface Movable {
    public void move();
}

public class Train implements Movable{
    public void move(){
        System.out.println("선로를 통해 이동");
    }
}

public class Bus implements Movable{
    public void move(){
        System.out.println("도로를 통해 이동");
    }
}

public class Client {
    public static void main(String args[]){
        Movable train = new Train();
        Movable bus = new Bus();

        train.move();
        bus.move();
    }
}

,책으로는 이해가 되지않아 우테코 영상의 내용을 설명하겠습니다. 우테코 코드 역시 객체 주입이 핵심이라는 것은 변하지 않습니다. 현재 이동 방법은 "선로"로 이동하는 방법과  "도로"로 이동하는 방법이 있습니다. 현재 기차는 선로를 통해 이동하며 버스는 도로를 통해 이동하고 있습니다. 하지만 시대가 변화여 기차가 도로에도 이동할 수 있게 발전하였습니다. 기차가 도로에서 이동할 수 있게 하기 위해  Train클래스의 move( )메소드를 "도로를 통해 이동"이라고 바꾸게 되면 OCP원칙을 위배하게 됩니다. 버스, 기차, 스포츠 카, 비행기가 도로와 선로를 마음대로 선택하여 이동하고 싶을 때는 어떻게 코드를 작성해야 할까?

public interface MovableStrategy {
    public void move();
}

public class Load implements MovableStrategy{
    @Override
    public void move() {
        System.out.println("도로를 통해 이동");
    }
}

public class Rail implements MovableStrategy {
    @Override
    public void move() {
        System.out.println("선로를 통해 이동");
    }
}

public class Moving {
    private MovableStrategy movableStrategy;

    public void move(){
        movableStrategy.move();
    }

    public void setMovableStrategy(MovableStrategy movableStrategy){
        this.movableStrategy = movableStrategy;
    }
}

public class Bus extends Moving {

}

public class Train extends Moving{

}

public class Client {
    public static void main(String args[]){
        Moving train = new Train();
        Moving bus = new Bus();

        // 기차 - 선로
        // 버스 - 도로

        train.setMovableStrategy(new Rail());
        bus.setMovableStrategy(new Load());

        train.move();
        bus.move();

        // 버스 - 선로
        bus.setMovableStrategy(new Rail());
        bus.move();
    }
}


해당 코드를 보면 버스가 자유롭게 도로와 선로를 다닐수 있습니다. 어떻게 보면 위 코드의 전략 패턴은 다형성과 관련이 많다고 생각합니다.  

더보기

 train.setMovableStrategy(new Rail());
 bus.setMovableStrategy(new Load());

매개 변수에 어떤 객체를 주입하냐에 따라 동일한 메소드가 다양하게 동작할수 있기 때문에 다형성과 관련이 있다고 생각합니다.

 

 

# 전략 패턴의 구성요소

1. 전략 메서드를 가진 객체

2. 전략 객체를 사용하는 컨텍스트

3. 전략 객체를 생성해 컨텍스트에 주입하는 클라이언트

 

어느정도 전략패턴에 대해 이해는 가지만 완벽하게 이해하지는 못하였습니다. 좀더 이해가 된다면 다시 전략패턴에 대해 정리하겠습니다. << 다시 생각해서 정리하기

 

# 장점과 단점

> 장점

1. 상속을 사용하지 않는다.

2. if-else 구문을 제거할 수 있다.

3. 구현의 선택이 가능하다

 

> 단점 

1. 객체수가 증가한다.

2. 서로 다른 전략을 이해 해야 한다.

 

# Reference

https://www.youtube.com/watch?v=zGJzEBOELoU&t=386s (우테코 전략패턴 설명)

https://victorydntmd.tistory.com/292 (블로그 설명 / 도로, 선로에 대한 코드)

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함