본문 바로가기

SoftwareDo/Java

[Console] 전략 (Strategy) 패턴

 오늘, 탬플릿 패턴과 함께 배운 전략 패턴을 포스팅하려고 합니다.
 전략 패턴은, 유사한 구조, 맥락(Context)을 가지는 여러개의 기능이 있을떄, 이 유사한 부분의 중복을 방지하기위한 방법입니다.

1. 전략 패턴?

 여러개의 전략을 만들고, 그 전략을 상황에 맞추어 교체 하는 방식 이라고 할까요, 실제 코딩으로 보자면

출처 : https://niceman.tistory.com/133

 이러한 구조라고 볼 수 있습니다. Client (main) 이 보통 다른 클래스인 Context (실제 맥락, 유사한 구조를 가지는 클래스) 의 메소드를 사용 합니다. 그런데 사용 할 때. 전략들을 객체화 하는 등, 만들어 주고 전략을 매개변수로써 넘겨줍니다.
 그러면, context 에서 공통적인 부분을 처리 하고 차이가 있는 부분들은 매개변수로 받은 전략을 통하여 처리를 합니다. 이때, 전략과 context 사이의 연계를 위한것이 인터페이스 입니다. 매개변수, 반환형 등을 통일해주는 역할이죠.

 이런 흐름을 가지는데. 여기서 인터페이스를 활용하여 클래스를 더 만들면, 그 클래스를 그대로 context에서 사용 할 수 있습니다. 그리고, 공통적인 부분들은 context 혹은 인터페이스 쪽을 수정해주면 되기에, 유지보수와 기능추가가 용이해집니다.

2. 실제 코드로 봅시다.

 먼저, 기초로써 볼 수 있는 "계산기"를 전략 패턴으로 만들어 보았습니다.
 이 계산기는, 두 수를 입력받고, 혹시 0 0 을 입력 받을시 종료되는 프로그램입니다. 0 0 이 아니라면, 그 유형에 따라 계산을 하고요.

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

package S200609;

 

import java.util.Scanner;

 

public class Calculator2 {

    public void execute(CalculatorStrategy Strategy) {

        Scanner scanner = new Scanner(System.in);

        while(true) {

            System.out.println("두 수를 입력하세요.");

            

            int value1 = scanner.nextInt();

            int value2 = scanner.nextInt();

            

            if(value1 == 0 && value2 == 0) {

                System.out.println("프로그램을 종료합니다.");

                break;

            }

            

            Strategy.Calculate(value1, value2);

        }

        scanner.close();

    }

    

    public static void main(String[] args) {

        Calculator2 calculate = new Calculator2();

        CalculatorStrategy strategy = new PlusStrategy();

        calculate.execute(strategy);

    }

}

 

Colored by Color Scripter

cs

(계산기2인데, 1은 탬플릿 패턴으로, 비교를 위해 개발했던 클래스 입니다.)
 위 순서도에서, context 부분입니다만 main 부분도 같이 포함되어 있습니다. 계산기의 공통적인 부분이라고 할 수 있는, 두 수를 입력 받고 만약 0 0 일시 종료하는 부분을 담고 있습니다. 그 외에는, 계산을 위해 인터페이스인 Strategy를 매개변수로 받는 부분이 있습니다.

 이 context의 execute, Calculate를 동작 시키기 위해서는 Strategy를 매개변수로 넘겨주어야 합니다. 그 부분은, main 문에서 CalculatorStrategy strategy = new PlusStrategy();calculate.execute(strategy); 부분이지요. 이 경우는, 더하기를 하고 출력 하는 부분을 따로 뺸 전략인, PlusStrategy 매개변수로써 넘겨준 것이에요.

 그러면, PlusStrategy 를 볼까요?

1

2

3

4

5

6

7

8

9

10

11

12

13

package S200609;

 

public class PlusStrategy implements CalculatorStrategy {

 

    @Override

    public void Calculate(int value1, int value2) {

        // TODO Auto-generated method stub

        int result = value1+value2;

        System.out.println(String.format("%d + %d = %d", value1 , value2, result));

    }

 

}

 

Colored by Color Scripter

cs

Calculator2 에서 PlusStrategy를 매개변수로 받고 Calculate() 를 실행을 한다면, int형 매개변수 두개가 전달이 되고, 계산과 출력이 이루어지게 됩니다.
 여기서, 더하기만 한다면 계산기라고 하기도 뭐하고, 전략 패턴을 쓰는 이유가 없겠죠? 빼기 기능을 추가해보곘습니다.

1

2

3

4

5

6

7

8

9

10

11

12

13

package S200609;

 

public class MinusStrategy implements CalculatorStrategy {

 

    @Override

    public void Calculate(int value1, int value2) {

        // TODO Auto-generated method stub

        int result = value1-value2;

        System.out.println(String.format("%d - %d = %d", value1 , value2, result));

    }

 

}

 

Colored by Color Scripter

cs

  PlusStrategy와 크게 차이없는 코드 입니다. 계산 부분과 출력 부분에 있던 +를 -로 바꿔주었을 뿐이지요. 그럼 이제 더하기를 하고 뺴기를 하는 코드를 메인에 추가 해보면,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public static void main(String[] args) {

        Calculator2 calculate = new Calculator2();

        CalculatorStrategy strategy = new PlusStrategy();

        calculate.execute(strategy);

        calculate.execute(new CalculatorStrategy() {

            

            @Override

            public void Calculate(int value1, int value2) {

                // TODO Auto-generated method stub

 

                int result = value1-value2;

 

                System.out.println(String.format("%d - %d = %d", value1 , value2, result));

            }

        });

    }

Colored by Color Scripter

cs

 main을 이렇게 쓸 수 있습니다. 어라? 그런데 마이너스 부분을 따로 객체화를 해주지 않고 인터페이스 그대로 객체화를 하고선, 중괄호 안에 Override 해주었네요?
 이렇게도 쓸 수 있습니다. 따로 클래스를 만들고, 따로 객체화를 해주는 대신에 인터페이스 그대로 new 를 해주니, 중괄호 안에 override를 해주는 방법도 있습니다.

 3. 이 패턴이 좋을까요?

 아직 저는 현업에 종사하고 있지 않습니다만, 선생님의 말씀과 여러 인식을 보았을떄. 배워두어서 나쁠 것 없는 패턴인 것 같습니다. 이 패턴을 알고 있다면, 코드의 가독성이 더 좋을 수도 있을 것 같고요.
 저의경우는, 전공이 C#인데 C# 에서또한 같은 방법, 어쩌면 더 좋은 방법으로 전략 패턴을 구현할 수 있을 것 같습니다. 

 P.s

 위의 계산기 예제 말고도, 실제 실무에서 쓸법한 DB 연결에 사용을 한 예제가 있습니다만, SQL과 DB에 대한 지식, 그리고 JDBC의 활용도 알아야 하기에... 다음에 기회가 될 때 정리하고자 합니다.