Home 전략 패턴(Strategy Pattern)
Post
Cancel

전략 패턴(Strategy Pattern)


전략 패턴이란?

  • 실행중에 알고리즘 전략을 선택하여 객체 동작을 실시간으로 바뀌도록 할 수 있게 하는 패턴이다.

전략 패턴은 OOP의 집합체

GOF의 디자인 패턴 책에서는 전략 패턴을 다음과 같이 정의한다.

  • 동일 계열의 알고리즘군을 정의하고 -> 전략 구현체로 정의
  • 각각의 알고리즘을 캡슐화하여 -> 인터페이스로 추상화
  • 이들을 상호 교환이 가능하도록 만든다. -> 합성(composition)으로 구성
  • 알고리즘을 사용하는 클라이언트와 상관없이 독립적으로-> 컨텍스트 객체 수정 없이
  • 알고리즘을 다양하게 변경할 수 있게 한다. -> 메소드를 통해 전략 객체를 실시간으로 변경함으로써 전략을 변경

구현 예제

BAD CASE

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
31
32
33
34
35
36
37
class TakeWeapon {
    public static final int SWORD = 0;
    public static final int SHIELD = 1;
    public static final int CROSSBOW = 2;

    private int state;

    void setWeapon(int state) {
        this.state = state;
    }

    void attack() {
        if (state == SWORD) {
            System.out.println("칼을 휘두르다");
        } else if (state == SHIELD) {
            System.out.println("방패로 밀친다");
        } else if (state == CROSSBOW) {
            System.out.println("석궁을 발사하다");
        }
    }
}


class User {
  public static void main(String[] args) {
    // 플레이어 손에 무기 착용 전략을 설정
    TakeWeapon hand = new TakeWeapon();

    // 플레이어가 검을 들도록 전략 설정
    hand.setWeapon(TakeWeapon.SWORD);
    hand.attack(); // "칼을 휘두르다"

    // 플레이어가 방패를 들도록 전략 설정
    hand.setWeapon(TakeWeapon.SHIELD);
    hand.attack(); // "방패로 밀친다"
  }
}

보기엔 직관적이고 괜찮아 보이지만,
새로운 무기가 추가되어 20개가 넘는상태가 된다고 가정하면. 분기 지옥에 빠질 수 있다.



GOOD CASE-1

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// 전략 - 추상화된 알고리즘  (1~3단계)
interface Weapon {
    void offensive();
}

class Sword implements Weapon {
    @Override
    public void offensive() {
        System.out.println("칼을 휘두르다");
    }
}

class Shield implements Weapon {
    @Override
    public void offensive() {
        System.out.println("방패로 밀친다");
    }
}

class CrossBow implements Weapon {
    @Override
    public void offensive() {
        System.out.println("석궁을 발사하다");
    }
}


// 컨텍스트 - 전략을 등록하고 실행 (4단계)
class TakeWeaponStrategy {
    Weapon wp;

    void setWeapon(Weapon wp) {
        this.wp = wp;
    }

    void attack() {
        wp.offensive();
    }
}


// 클라이언트 - 전략 제공/설정  (5단계)
class User {
    public static void main(String[] args) {
        // 플레이어 손에 무기 착용 전략을 설정
        TakeWeaponStrategy hand = new TakeWeaponStrategy();

        // 플레이어가 검을 들도록 전략 설정
        hand.setWeapon(new Sword());
        hand.attack(); // "칼을 휘두르다"

        // 플레이어가 방패를 들도록 전략 변경
        hand.setWeapon(new Shield());
        hand.attack(); // "방패로 밀친다"

        // 플레이어가 석궁을 들도록 전략 변경
        hand.setWeapon(new Crossbow());
        hand.attack(); // "석궁을 발사하다"
    }
}



GOOD-CASE2

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 전략 인터페이스
public interface SortingStrategy {
    void sort(int[] array);
}

// 전략 클래스 구현
public class BubbleSort implements SortingStrategy {
    public void sort(int[] array) {
        // 버블 정렬 구현
    }
}

public class QuickSort implements SortingStrategy {
    public void sort(int[] array) {
        // 퀵 정렬 구현
    }
}

// 매개체 클래스
public class Sorter {
    private SortingStrategy strategy;

    public void setStrategy(SortingStrategy strategy) {
        this.strategy = strategy;
    }

    public void executeStrategy(int[] array) {
        strategy.sort(array);
    }
}

public class Main {
  public static void main(String[] args) {
    Sorter sorter = new Sorter();

    // 버블 정렬 전략 설정
    sorter.setStrategy(new BubbleSort());
    int[] array1 = {5, 3, 1, 4, 2};
    sorter.executeStrategy(array1);

    // 퀵 정렬 전략 설정
    sorter.setStrategy(new QuickSort());
    int[] array2 = {5, 3, 1, 4, 2};
    sorter.executeStrategy(array2);
  }
}

클라이언트 코드는 매개체 클래스를 통해 각 전략을 사용할 수 있다.
전략 패턴을 사용하면 전략을 유연하게 변경하고 확장할 수 있으며,
클라이언트 코드와 전략의 결합도를 낮출 수 있다.


마치며

  • 전략이 늘어날수록 관리해야할 객체의 수가 증가한다.
  • 만일 단순한 전략이라면 굳이 해당 패턴을 적용할 필요가 없다.

참고

This post is written by PRO.