ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java Design Pattern - 전략 패턴(Strategy Pattern)
    Language/Java Design Pattern 2022. 11. 18. 15:02

    전략 패턴(Stratgy Pattern)

    전략 패턴이란?

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

    다시 말해, 객체가 할 수 있는 행위들 각각을 전략으로 만들어 놓고, 동적으로 행위의 수정이 필요한 경우 전략을 바꾸는 것만으로 행위의 수정이 가능하도록 만든 패턴이다.

     

    전략 패턴의 사용 이유

     

    위 다이어그램과 같이 기차(Train)와 버스(Bus) 클래스가 있고, 이 두 클래스는 Movable 인터페이스를 구현하고 있는 구조이다.

     

    public interface Movable {
        public String Move();
    }
    public class Train implements Movable {
        @Override
        public String move() {
            return "선로를 통해서 이동";
        }
    }
    public class Bus implements Movable {
        @Override
        public String move() {
            return "도로를 통해서 이동";
        }
    }
    public class Client {
        public static void main(String[] args) {
            Movable bus = new Bus();
            Movable train = new Train();
            
            System.out.println(bus.move());   // "도로를 통해서 이동" 출력
            System.out.println(train.move());   // "선로를 통해서 이동" 출력
        }
    }

    해당 구조를 코드로 표현하면 위와 같다.

     

    버스는 도로를 따라 이동하고, 기차는 선로를 따라 이동한다. 이후 시간이 흘러 선로를 따라 움직이는 버스가 개발되었다고 가정해 보겠다.

     

    public class Bus {
        @Override
        public String move() {
            return "선로를 따라 이동";
        }
    }

    그렇다면, Bus 클래스의 move() 메서드를 위와 같이 바꿔주기면 하면 된다.

     

    하지만, 위와 같은 방식은 SOLID의 원칙 중 OCP(Open-Closed Principle)에 위배된다. OCP에 의하면 기존의 move() 메서드를 수정하지 않으면서 행위가 수정되어야 하지만, 지금은 Bus 클래스의 move() 메서드를 직접 수정했다.

     

    또한, 지금과 같은 방식의 변경은 시스템이 확장되었을 때 유지보수를 어렵게 한다.

    예를 들어, 버스와 같이 도로를 따라 움직이는 택시, 자가용, 오토바이 등이 추가된다고 할 때, 모두 버스와 같은 move() 메서드를 사용한다. 만약 선로를 따라 움직이는 버스와 같이 선로를 따라 움직이는 택시, 자가용, 오토바이 등이 개발된다면, 같은 move() 메서드를 여러 클래스에서 똑같이 사용하고 있기 때문에, 해당 메서드를 일일이 수정해야 한다.

     

    즉, 지금과 같은 수정 방식의 문제점은 다음과 같다.

     

    1. OCP 위배

    2. 시스템이 커져서 확장이 될 경우 메서드의 중복 문제

     

    따라서, 위와 같은 문제점을 해결하고자 전략 패턴을 사용한다.

     

    전략 패턴 구현

    이번에는 선로를 따라 이동하는 버스가 개발된 상황에서 시스템이 유연하게 변경되고 확장될 수 있도록 전략 패턴을 사용해보도록 하겠다.

     

     

    현재는 선로를 따라 움직이는 방식과 도로를 따라 움직이는 방식 두 가지가 있다. 움직이는 두 가지 방식에 대해 Strategy 클래스(RailLoadStrategy, LoadStrategy)를 생성하도록 한다.

    그리고 두 클래스는 move() 메서드를 통해 어떤 경로로 움직이는에 대해 구현한다. 또한, 두 전략 클래스를 캡슐화하기 위해 MovableStrategy 인터페이스를 생성한다.

     

    public interface MovableStrategy {
        public String move();
    }
    public class RailLoadStrategy implements Movable {
        @Override
        public String move() {
            return "선로를 통해서 이동";
        }
    }
    public class LoadStrategy implements Movable {
        @Override
        public String move() {
            return "도로를 통해서 이동";
        }
    }

    구조를 코드로 구현하면 위와 같다.

     

     

    다음으로는 운송 수단에 대한 클래스를 정의할 차례이다.

    기차, 버스와 같은 운송 수단은 move() 메서드를 통해 움직일 수 있다. 각 운송 수단에 대한 이동 방식은 직접 메서드를 통해 구현하는 것이 아닌, 어떻게 움직일 것인지에 대한 전략을 설정하여, 그 전략의 움직임 방식을 사용하도록 한다.

    따라서, 전략을 설정하는 메서드인 setMovableStrategy()가 존재한다.

     

    public class Moving {
        private MovableStrategy movableStrategy;
        
        public String move() {
            return this.movableStrategy.move();
        }
        
        public void setMovableStrategy(MovableStrategy movableStrategy) {
            this.movableStrategy = movableStrategy;
        }
    }
    public class Train extends Moving {
    }
    public class Bus extends Moving {
    }

    구조를 코드로 구현하면 위와 같다.

     

    public class Client {
        public static void main(String[] args) {
            Moving train = new Train();
            Moving bus = new Bus();
            
            /** 기존의 기차와 버스의 이동 방식 */
            train.setMovableStrategy(new RailLoadStrategy());
            bus.setMovableStrategy(new LoadStrategy());
            
            train.move();   // "선로를 따라 이동" 출력
            bus.move();   // "도로를 따라 이동" 출력
            
            /** 선로를 따라 이동하는 버스가 개발 */
            bus.setMovableStrategy(new RailLoadStrategy());
            bus.move();   // "선로를 따라 이동" 출력
        }
    }

    위와 같이 전략 패턴을 사용하면 로직이 변경되었을 때, 객체가 사용하고자 하는 전략을 수정하기만 하면 되기 때문에 유연하게 수정이 가능하다.


    출처

    https://victorydntmd.tistory.com/292

     

    728x90

    댓글

Designed by Tistory.