Strategy (전략 패턴)

|

Strategy Pattern

전략이라는 의미이다.
특정 문제를 해결하기 위하여 알고리즘을 구현한 부분을 모두 교환할 필요가 있을때 사용한다.

예) 게임 가위바위보에서 가위/바위/보를 내는 전략 변경

예를 들어 출퇴근을 하는데 간단하게 가장 환승이 적은 전략 / 가장 빨리 가는 전략 / 랜덤으로 선택하여 가는 전략을 프로그래밍 해보겠다.

public class Main {

    public static void main(String[] args) {
        Employee employee = new Employee("Ran", new MinTransferStrategy());
        Transport transport = employee.getMethod(100, 200);
        System.out.println("MinTransferStrategy() : " + transport);

        employee = new Employee("Ran", new FastestStrategy());
        transport = employee.getMethod(100, 200);
        System.out.println("FastestStrategy() : " + transport);

        employee = new Employee("Ran", new RandomStrategy());
        transport = employee.getMethod(100, 200);
        System.out.println("RandomStrategy() : " + transport);
    }
}

Employee Ran은 3번 출근을 하는데 각각 다른 전략을 선택한다. 적은 환승 / 빠른 길 / 랜덤 전략

public class Employee {
    private String name;
    private Strategy strategy;

    public Employee(String name, Strategy strategy) {
        this.name = name;
        this.strategy = strategy;
    }

    public Transport getMethod(int startCode, int endCode) {
        return strategy.getMethod(startCode, endCode);
    }
}
public interface Strategy {
    Transport getMethod(int startCode, int endCode);
}

전략의 인터페이스. 하나의 메소드를 가지고 있고 출발 위치와 도착 위치 코드를 가지고 있다.

public class FastestStrategy implements Strategy {

    @Override
    public Transport getMethod(int startCode, int endCode) {
        return Transport.getFastestTransport(startCode, endCode);
    }
}
public class MinTransferStrategy implements Strategy {

    @Override
    public Transport getMethod(int startCode, int endCode) {
        return Transport.getComfortTransport(startCode, endCode);
    }
}

각각의 전략 인터페이스를 구현한 구현 클래스. 전략에 따라 각각 필요한 메소드를 호출한다.

public class RandomStrategy implements Strategy {

    private Random random = new Random();

    @Override
    public Transport getMethod(int startCode, int endCode) {
        int n = random.nextInt(4);
        return Transport.getTransport(n);
    }
}

랜덤 전략은 말그대로 아무거나 선택한다.

public class Transport {

    public static final int TRANSPORT_WALK = 0;
    public static final int TRANSPORT_BUS = 1;
    public static final int TRANSPORT_METRO = 2;
    public static final int TRANSPORT_BIKE = 3;

    private int currentTransport;

    public static final Transport[] transports = {
        new Transport(TRANSPORT_WALK),
        new Transport(TRANSPORT_BUS),
        new Transport(TRANSPORT_METRO),
        new Transport(TRANSPORT_BIKE),
    };

    public Transport(int num) {
        currentTransport = num;
    }

    public static Transport getTransport(int n) {
        return transports[n];
    }

    public static int getTotalTimeUsingTransport(int n, int startCode, int endCode) {
        switch (n) {
            case TRANSPORT_WALK:
                return 200;
            case TRANSPORT_BUS:
                return 100;
            case TRANSPORT_METRO:
                return 150;
            case TRANSPORT_BIKE:
                return 180;
        }
        return 0;
    }

    public static int getTotalTransferUsingTransport(int n, int startCode, int endCode) {
        switch (n) {
            case TRANSPORT_WALK:
                return 0;
            case TRANSPORT_BUS:
                return 3;
            case TRANSPORT_METRO:
                return 2;
            case TRANSPORT_BIKE:
                return 1;
        }
        return 0;
    }

    // get fast way
    public static Transport getFastestTransport(int startCode, int endCode) {
        int minimumIndex = -1;
        int min = 999;

        for(int i =0; i < 4; i++) {
            int n = getTotalTimeUsingTransport(i, startCode, endCode);
            if(n < min) {
                min = n;
                minimumIndex = i;
            }
        }
        return Transport.getTransport(minimumIndex);
    }

    // get minimum transfer way
    public static Transport getComfortTransport(int startCode, int endCode) {
        int minimumIndex = -1;
        int min = 999;

        for(int i =0; i < 4; i++) {
            int n = getTotalTransferUsingTransport(i, startCode, endCode);
            if(n < min) {
                min = n;
                minimumIndex = i;
            }
        }
        return Transport.getTransport(minimumIndex);
    }

    @Override
    public String toString() {
        return "Transport{" + "currentTransport=" + currentTransport + '}';
    }
}

교통편에 따라 달라지는 시간 또는 환승 개수를 리턴한다.
실제로 이런 프로그램을 구현한다면 startCode와 endCode에 따라 달라지는 시간을 가져오도록
서버에서 API를 호출해야 하겠지만 strategy 패턴을 이해하는 목적의 코드이므로 간단하게 작성하였다.