[디자인패턴] 전략패턴(Strategy Pattern)

고지훈·2021년 8월 31일
3

DesignPattern

목록 보기
1/16
post-thumbnail

전략패턴(Strategy Pattern)

전략패턴은 각각의 알고리즘군을 교환이 가능하도록 별도로 정의하고 각각 캡슐화한 후 서로 교환해서 사용할 수 있는 패턴이며, 아래와 같은 장점이 있다.

  1. 코드 중복 방지
  2. 런타임(Runtime)시에 타겟 메소드 변경
  3. 확장성(신규 클래스) 및 알고리즘 변경 용이

객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화하는 인터페이스를 정의하여, 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법을 말한다.


왜, 전략패턴을 사용할까?

아래의 그림은 전략패턴을 이해하기 위한 예제로, Train클래스와 Bus클래스는 Movable인터페이스를 상속받아 구현하고 있고 Client클래스는 Train클래스와 Bus클래스를 사용하기 위한 주체이다.

위 UML다이어그램을 아래의 코드와 같이 구현할 수 있다.

// Movable.java
public interface Movable {
    public void move();
}
// Train.java
public class Train implements Movable {
    @Override
    public void move() {
        System.out.println("선로를 따라 움직입니다.");
    }
}
// Bus.java
public class Bus implements Movable {
    @Override
    public void move() {
        System.out.println("도로를 따라 움직입니다.");
    }
}
// Client.java
public class Client {
    public static void main(String args[]){
    	Movable Train = new Train();
        Movable Bus = new Bus();
        
        train.move(); // 결과: 선로를 따라 움직입니다.
        bus.move(); // 결과: 도로를 따라 움직입니다.
    }
}

해당 코드를 실행하면, Train클래스의 move메소드와 Bus클래스의 move메소드가 한 번씩 호출되어 기차는 선로를 따라 움직이고, 버스는 도로를 따라 움직일 것이다.

만약 트램과 같이 선로를 따라 이동하는 버스가 추가 될 경우, 어떤 방향으로 수정하면 좋을까? => Bus클래스의 move메소드를 수정하면 될 것이다.

하지만 이 방식으로 수정하게 될 경우 SOLID의 원칙 중 OCP(Open-Closed Principle)에 위배된다.

*SOLID-OCP(개방 폐쇄 원칙)

  • 소프트웨어 엔티티(클래스, 모듈, 함수)는 확장에 대해서는 열려있어야 하지만 변경에 대해서는 닫혀 있어야 한다. 이는 interface를 통해 구현하여 해결한다.
  • 예를 들어, 상점 아르바이트생이 바뀐다고 해도 손님은 물건을 구매하는데 지장이 없다. 상점 아르바이트생은 판매 인터페이스를 구현해야하기 때문이다. 즉, 손님은 판매 인터페이스와 소통하기 때문에 아르바이트생이 누구든 상관없다.

위의 개념을 적용할 때, 트램과 같이 선로를 따라 이동하는 버스가 존재할 경우, 기존의 move()를 수정하지 않으며 행위를 수정해야한다.

또한 시스템이 확장될 경우 유지보수의 문제가 발생할 수 있다.

따라서 위와 같은 코드 수정은 두 가지 문제를 발생시킬 수 있다.
1. SOLID - OCP위배
2. 시스템 확장이 발생할 경우 중복 메서드의 발생
이와 같은 상황을 해결하기 위해 전략패턴(Strategy Pattern)을 사용한다.


전략패턴 구현

현재 운송수단은 선로를 따라 이동하는 방법과, 도로를 따라 이동하는 방법이 있다.
즉, 운송수단의 움직이는 방식은 두가지임으로 두 방식에 대해 Strategy클래스를 생성한다.

두 클래스는 TransportStrategy를 상속받아 move메소드를 구현한다. 이렇게 캡슐화하는 이유는 운송수단에 대한 전략뿐만 아니라, 다른 전략들이 추가적으로 확장되는 경우를 고려한 설계 방법이기 때문이다.

위 UML다이어그램을 아래의 코드와 같이 구현할 수 있다.

// TransportStrategy.java
public interface TransportStrategy {
    public void move();
}
// LoadStrategy.java
public class LoadStrategy implements TransportStrategy {
    @Override
    public void move() {
        System.out.println("도로를 따라 움직입니다.");
    }
}
// RailLoadStrategy.java
public class RailLoadStrategy implements TransportStrategy {
    @Override
    public void move() {
        System.out.println("선로를 따라 움직입니다.");
    }
}

다음으로 운송 수단에 대한 클래스를 정의해야한다.

기차와 버스 모두 move()메서드를 통해 움직일 수 있다.
제일 위의 예제와 같이 각 클래스 내부에 move()메소드를 구현하는것이 아닌 어떻게 움직일 것인지에 대한 전략을 설정해, 그 전략의 움직임방식을 사용해 움직이도록 한다.

여기서 setTransportStrategy()는 전략을 설정시켜 줄 메소드이다.

위 UML다이어그램을 아래의 코드와 같이 구현할 수 있다.

// moving.java
public class Moving {
    private TransportStrategy tranportStrategy;

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

    public void setTransportStrategy(TransportStrategy transportStrategy) {
        this.transportStrategy = transportStrategy;
    }
}
// Bus.java
public class Bus extends Moving {

}
// Train.java
public class Train extends Moving {

}

마지막으로 운송수단을 이용할 Client클래스를 구현할 차례이다.

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

        train.setTransportStrategy(new RailLoadStrategy());
        bus.setTransportStrategy(new LoadStrategy());

        train.move(); // 결과: 선로를 따라 이동합니다.
        bus.move(); // 결과: 도로를 따라 이동합니다.

        // 트램과 같은 선로를 달리는 버스가 나타날 경우
        bus.setTransportStrategy(new RailLoadStrategy());
        bus.move(); // 결과: 선로를 따라 이동합니다.
    }
}

위의 코드에서 보았듯이, 새로운 전략을 사용해야할 경우 기존에 선언된 운송수단 객체에 새로운 전략을 적용시킴으로써 새로운 방법의 운송방법이 나타났을 경우 적용시킬 수 있다.

또한, 위와 같이 전략 패턴을 구현하게 될 경우 주유 방법(전기, 기름)등 운송수단에 필요한 다양한 전략을 적용시킬 수 있다.

전략 패턴 학습 시 참고 블로그: https://victorydntmd.tistory.com/292

profile
"계획에 따르기보다 변화에 대응하기를"

1개의 댓글

comment-user-thumbnail
2021년 9월 8일

재밌게 읽었습니다. 전략 패턴이라는 게 의존성 주입이랑 많이 닮아 보이네요?

답글 달기