본문 바로가기
Computer Sience/Desgin Pattern

[Design Pattern] 전략 (Strategy) 패턴

by 제우제우 2024. 11. 25.

전략 (Strategy) 패턴

여러 알고리즘을 캡슐화하고 상호 교환 가능하게 만드는 패턴

컨텍스트에서 사용할 알고리즘을 클라이언트가 선택한다. 

전략 (Strategy) 패턴 before

BlueLightRedLight 무궁화 꽃 게임

public class BlueLightRedLight {
    private int speed;
    public BlueLightRedLight(int speed){
        this.speed = speed;
    }
    public void blueLight(){
        if(speed == 1) System.out.println("무 궁 화    꽃   이");
        else if(speed == 2) System.out.println("무궁화꽃이");
        else System.out.println("무광꼬치");
    }
    public void redLight() {
        if (speed == 1) System.out.println("피 었 습 니  다.");
        else if (speed == 2) System.out.println("피었습니다.");
        else System.out.println("피어씀다");
    }
}

 

단순하게 속도에 따라서 출력 속도를 다르게 한다.

이렇게 간단한 클래스가 아니라 만약 실제 비즈니스 로직이고 전략(여기서 속도)에 따라 다르게 동작한다고 하면 

코드의 가독성이 많이 떨어질 것이다. 

이는 상태 패턴(State Pattern)에서 나타나는 단점과 거의 비슷하다. 

전략 (Strategy) 패턴 after

Context

public class BlueLightRedLight {
    public void blueLight(Speed speed){
        speed.blueLight();
    }
    public void redLight(Speed speed) {
        speed.redLight();
    }
}

 

Strategy 인터페이스

public interface Speed {
    void blueLight();
    void redLight();
}

 

Strategy 인터페이스 구현체들

public class Normal implements Speed {
    @Override
    public void blueLight() {
        System.out.println("무 궁 화    꽃   이");
    }
    @Override
    public void redLight() {
        System.out.println("피 었 습 니  다.");
    }
}

public class Faster implements Speed {
    @Override
    public void blueLight() {
        System.out.println("무궁화꽃이");
    }
    @Override
    public void redLight() {
        System.out.println("피었습니다.");
    }
}

 

클라이언트 

public class Client {
    public static void main(String[] args) {
        BlueLightRedLight game = new BlueLightRedLight();
        game.blueLight(new Normal());
        game.redLight(new Faster());
    }
}

 

원하는 전략을 이렇게 사용 가능하다. 

전략이 추가되더라도 context 즉, BlueLightRedLight 클래스는 변경이 없다. OCP!!

 

익명 클래스 사용

public class Client {
    public static void main(String[] args) {
        BlueLightRedLight game = new BlueLightRedLight();
        game.blueLight(new Speed() {
            @Override
            public void blueLight() {
                System.out.println("무광꼬치");
            }

            @Override
            public void redLight() {
                System.out.println("피어씀다.");
            }
        });
    }
}

 

굳이 클래스를 정의하지 않고 이렇게 익명 클래스를 활용하여 전략을 넣어줄 수 있다.

만약 전략이 1개의 메소드 정의만을 요구한다면 함수형 인터페이스이기 때문에 람다식을 통해 더욱 간편하게 구현할 수 있다.

전략 (Strategy) 패턴 장단점 

장점

새로운 전략을 추가하더라도 기존 코드를 변경하지 않는다

상속 대신 위임을 사용할 수 있다

런타임에 전략을 변경할 수 있다

 

단점

복잡도가 증가한다

클라이언트 코드가 구체적인 전략을 알아야 한다

전략 (Strategy) 패턴 적용 사례

Comparator

public class JavaComparator {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(100);
        numbers.add(21);
        numbers.add(102);
        System.out.println(numbers); // 100, 21, 102

        Collections.sort(numbers, (o1, o2) -> o1 - o2);
        System.out.println(numbers); // 21, 100, 102
    }
}