Post

โ›“๏ธ Java Design-Pattern โ…ช - Strategy

โ›“๏ธ Java Design-Pattern โ…ช - Strategy

๐Ÿ“— ใ€ŽJAVA ์–ธ์–ด๋กœ ๋ฐฐ์šฐ๋Š” ๋””์ž์ธ ํŒจํ„ด : ์‰ฝ๊ฒŒ ๋ฐฐ์šฐ๋Š” GoF์˜ 23๊ฐ€์ง€ ๋””์ž์ธ ํŒจํ„ดใ€๋ฅผ ์ฝ๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

Strategy ํŒจํ„ด์ด๋ž€?

  • ์Šค์œ„์น˜๋ฅผ ์ „ํ™˜ํ•˜๋“ฏ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐ”๊ฟ”์„œ, ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํŒจํ„ด์ด๋‹ค.

์˜ˆ์ œ ํ”„๋กœ๊ทธ๋žจ

  • ๋‹ค์Œ์€ ์ปดํ“จํ„ฐ๋กœ ๊ฐ€์œ„๋ฐ”์œ„๋ณด๋ฅผ ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

Handย ํƒ€์ž…

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
public enum Hand {
	ROCK("๋ฐ”์œ„", 0),
    SCISSORS("๊ฐ€์œ„", 1),
    PAPER("๋ณด", 2);
    
    private String name;
    private int handValue;
    
    private static Hand[] hands = {
    	ROCK, SCISSORS, PAPER
    };
    
    private Hand(String name, int handValue) {
    	this.name = name;
        this.handValue = handValue;
    }
    
    public static Hand getHand(int handValue) {
    	return Hands[handValue];
    }
    
    public boolean isStrongerThan(Hand h) {
    	return fight(h) == 1;
    }
    
    public boolean isWeakerThan(Hand h) {
    	return fight(h) == -1;
    }
    
    private int fight(Hand h) {
    	if (this == h) {
        	return 0;
        } else if ((this.handValue + 1) % 3 == h.handValue) {
        	return 1;
        } else {
        	return -1;
        }
    }
    
    @Override
    public String toString() {
    	return name;
    }
}
  • ๊ฐ€์œ„๋ฐ”์œ„๋ณด์˜ ์†์„ ๋‚˜ํƒ€๋‚ด๋Š”ย enumํ˜•์œผ๋กœ ๊ฐ€์œ„, ๋ฐ”์œ„, ๋ณด๋ฅผ ๊ฐ๊ฐย SCISSORS,ย ROCK,ย PAPER๋ผ๋Š”ย enumย ์ƒ์ˆ˜๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค.ย 
  • getHandย ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ 0, 1, 2๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ฃผ๋ฉดย Handํ˜•์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
  • ์ด ๊ตฌ์กฐ๋Š”ย Singletonย ํŒจํ„ด์˜ ์ผ์ข…์ด๋‹ค.
  • ๋˜ํ•œย getHandย ๋ฉ”์†Œ๋“œ๋Š”ย static Factory Method๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • isStrongerThan,ย isWeakerThan์€ ์†์˜ ๊ฐ•์•ฝ์„ ๋น„๊ตํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.
  • ๋‹ค๋งŒ ์‹ค์ œ๋กœ ์†์˜ ๊ฐ•์•ฝ์„ ํŒ๋‹จํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋Š”ย flight์ด๋‹ค.

Strategyย ์ธํ„ฐํŽ˜์ด์Šค

1
2
3
4
public interface Strategy {
	public abstract Hand nextHand();
    public abstract void study(boolean win);
}
  • ๊ฐ€์œ„๋ฐ”์œ„๋ณด ์ „๋žต์„ ์œ„ํ•œ ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ๋ชจ์€ ์ด๋‹ค.
  • nextHand๋Š” ๋‹ค์Œ์— ๋‚ผ ์†์„ ์–ป๊ธฐ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ์ด๋‹ค.
  • ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ตฌํ˜„์ฒด์— ํ•ด๋‹นํ•˜๋Š” ์ „๋žต์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • strategy๋Š” ์ง์ „์— ๋‚ธ ์†์œผ๋กœ ์ด๊ฒผ๋Š”์ง€ ์กŒ๋Š”์ง€๋ฅผ ํ•™์Šตํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.

WinningStrategyย ํด๋ž˜์Šค

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.Random;

public class WinningStrategy implements Strategy {
	private Random random;
    private boolean won = false;
    private Hand prevHand;
    
    public WinningStrategy(int seed) {
    	random = new Random(seed);
    }
    
    @Override
    public Hand nextHand() {
    	if (!won) {
        	prevHand = Hand.getHand(random.nextInt(3));
        }
        return prevHand;
    }
    
    @Override
    public void study(boolean win) {
    	won = win;
    }
}
  • Strategyย ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ํด๋ž˜์Šค ์ค‘ ํ•˜๋‚˜์ด๋‹ค.
  • ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋Š” ๊ฒƒ์€ย nextHand,ย study๋ผ๋Š” ๋‘ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
  • ์ด ํด๋ž˜์Šค๋Š” ์ด์ „ ์Šน๋ถ€์— ์ด๊ธธ ๊ฒฝ์šฐ, ๋‹ค์Œ์—๋„ ๊ฐ™์€ ์†์„ ๋‚ด๋Š” ์ „๋žต์„ ์ทจํ•œ๋‹ค.
  • ๋งŒ์•ฝ ์ด์ „ ์Šน๋ถ€์—์„œ ์กŒ๋‹ค๋ฉด, ๋‹ค์Œ ์†์€ ๋‚œ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ์ •ํ•œ๋‹ค.

ProbStrategyย ํด๋ž˜์Šค

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
import java.util.Random;

public class ProbStrategy implements Strategy {
	private Random random;
    private int prevHandValue = 0;
    private int currentHandValue = 0;
    private int[][] history = {
    	{1, 1, 1},
        {1, 1, 1},
        {1, 1, 1}
    };
    
    public ProbStrategy(int seed) {
    	random = new Random(seed);
    }
    
    @Override
    public Hand nextHand() {
    	int bet = random.nextInt(getSum(currentHandValue));
        int handValue = 0;
        if (bet < history[currentHandValue][0]) {
        	handValue = 0;
        } else if (bet < history[currentHandValue][0] + history[currentHandValue][1]) {
        	handValue = 1;
        } else {
        	handValue = 2;
        }
        prevHandValue = currentHandValue;
        currentHandValue = handValue;
        
        return Hand.getHand(handValue);
    }
    
    private int getSum(int handValue) {
    	int sum = 0;
        for (int i = 0; i < 3; i++) {
        	sum += history[handValue][i];
        }
        
        return sum;
    }
    
    @Override
    public void study(boolean win) {
    	if (win) {
        	history[prevHandValue][currentHandValue]++;
        } else {
        	history[prevHandValue][(currentHandValue + 1) % 3]++;
            history[prevHandValue][(currentHandValue + 2) % 3]++;
        }
    }
}
  • ProbStrategyย ํด๋ž˜์Šค๋Š” ๋˜ ํ•˜๋‚˜์˜ ๊ตฌ์ฒด์ ์ธ ์ „๋žต์ด๋‹ค.
  • ๊ณผ๊ฑฐ์˜ ์ด๊ธฐ๊ณ  ์ง„ ์ „์ ์„ ํ™œ์šฉํ•ด์„œ ์† ๋‚ผ ํ™•๋ฅ ์„ ๋ฐ”๊พผ๋‹ค.
  • historyย ํ•„๋“œ๋Š” ๊ณผ๊ฑฐ์˜ ์ŠนํŒจ๋ฅผ ๋ฐ˜์˜ํ•œ ํ™•๋ฅ  ๊ณ„์‚ฐ์„ ์œ„ํ•œ ํ‘œ๋กœ ๋˜์–ด ์žˆ๋‹ค.
  • ๊ฐ ์ฐจ์›์˜ย index๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค.
1
2
3
4
5
6
history[์ง์ „์— ๋‚ธ ์†][์ด๋ฒˆ์— ๋‚ผ ์†]

// ์˜ˆ์‹œ
history[0][0] == 3
history[0][1] == 5
history[0][2] == 7

๊ฐ€๋ น ์œ„์˜ ์˜ˆ์‹œ์™€ ๊ฐ™์€ ๊ฐ’์ด ์žˆ๋‹ค๋ฉด,ย nextHandย ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ ๋‚œ์ˆ˜๊ฐ€ 3 ๋ฏธ๋งŒ์ด๋ฉด ๋ฐ”์œ„, 3 ์ด์ƒ 8 ๋ฏธ๋งŒ์ด๋ฉด ๊ฐ€์œ„, 8 ์ด์ƒ 15 ๋ฏธ๋งŒ์ด๋ฉด ๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Playerย ํด๋ž˜์Šค

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 class Player {
	private String name;
    private Strategy strategy;
    private int winCount;
    private int loseCount;
    private int gameCount;
    
    public Player(String name, Strategy strategy) {
    	this.name = name;
        this.strategy = strategy;
    }
    
    public Hand nextHand() {
    	return strategy.nextHand();
    }
    
    public void win() {
    	strategy.study(true);
        winCount++;
        gameCount++;
    }
    
    public void lose() {
    	strategy.study(false);
        loseCount++;
        gameCount++;
    }
    
    public void even() {
    	gameCount++;
    }
    
    @Override
    public String toString() {
    	return "[" 
        	+ name 
            + ":" 
            + gameCount 
            + " games, " 
            + winCount 
            + " win, " 
            + loseCount 
            + " lose" 
            + "]";
    }
}
  • ๊ฐ€์œ„๋ฐ”์œ„๋ณดํ•˜๋Š” ์‚ฌ๋žŒ์„ ํ‘œํ˜„ํ•œ ํด๋ž˜์Šค์ด๋‹ค.
  • ์ฃผ์–ด์ง„ย name๊ณผย strategy๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.
  • nextHand๋Š” ๋‹ค์Œ ์†์„ ์–ป๋Š” ๋ฉ”์†Œ๋“œ์ธ๋ฐ, ์‹ค์ œ๋กœ ๋‹ค์Œ ์†์€ ์ธ์Šคํ„ด์Šค์˜ย strategy๊ฐ€ ๊ฒฐ์ •ํ•œ๋‹ค.
  • ์ฆ‰ย Stretegy์—๊ฒŒ ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•˜๊ณ  ์žˆ๋‹ค.
  • ์ด๊ธฐ๊ฑฐ๋‚˜, ์งˆ ๊ฒฝ์šฐย strategyย ํ•„๋“œ๋ฅผ ํ†ตํ•ดย studyย ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.ย 
  • XXCountย ํ•„๋“œ๋Š” ํ”Œ๋ ˆ์ด์–ด์˜ ์Šน์ˆ˜๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.

Mainย ํด๋ž˜์Šค

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
public class Main {
	public static void main(String[] args) {
    	if (args.length != 2) {
        	System.out.println("Usage : java Main randomseed1 randomseed2");
            System.out.println("Example : java Main 314 15");
            System.exit(0);
        }
        
        int seed1 = Integer.parseInt(args[0]);
        int seed2 = Integer.parseInt(args[1]);
        
        Player player1 = new Player("KIM", new WinningStrategy(seed1));
        Player player2 = new Player("LEE", new ProbStrategy(seed2));
        
        for (int i = 0; i < 10000; i++) {
        	Hand nextHand1 = player1.nextHand();
            Hand nextHand2 = player2.nextHand();
        
        	if (nextHand1.isStrongerThan(nextHand2)) {
            	System.out.println("Winner : " + player1);
                player1.win();
                player2.lose();
            } else if (nextHand2.isStrongerThan(nextHand1)) {
            	System.out.println("Winner : " + player2);
                player1.lose();
                player2.win();
            } else {
            	System.out.println("Even...");
                player1.even();
                player2.even();
            }
        }
        
        System.out.println("Total result : ");
        System.out.println(player1);
        System.out.println(player2);
    }
}
  • ์‹ค์ œ ๋‘ ๋ช…์˜ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๊ฐ€์œ„๋ฐ”์œ„๋ณด๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ํด๋ž˜์Šค์ด๋‹ค.

Strategyย ํŒจํ„ด์˜ ๋“ฑ์žฅ์ธ๋ฌผ

Strategyย ์ธํ„ฐํŽ˜์ด์Šค

  • ์ „๋žตย Strategyย ์—ญํ• ์„ ๋งก์•„ ์ „๋žต์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.

WinningStrategy,ย ProbStrategyย ํด๋ž˜์Šค

  • ์ „๋žต ์—ญํ• ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ์ „๋žตย ConcreteStrategyย ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ์—ฌ๊ธฐ์„œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋“ฑ ์‹ค์ œ ์ „๋žต์„ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•œ๋‹ค.

Playerย ํด๋ž˜์Šค

  • ์ „๋žต ์—ญํ• ์„ ์ด์šฉํ•˜๋Š” ๋ฌธ๋งฅย Contextย ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ๊ตฌ์ฒด์ ์ธ ์ „๋žต ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค๊ฐ€ ํ•„์š”์— ๋”ฐ๋ผ์„œ ์ด์šฉํ•œ๋‹ค.

์ฑ…์—์„œ ์ œ์‹œํ•˜๋Š” ํžŒํŠธ

์ผ๋ถ€๋Ÿฌย Strategyย ์—ญํ• ์„ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์žˆ์„๊นŒ?

  • ๊ฐ€๋ น ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ฐœ๋Ÿ‰ํ•ด์„œ ๋” ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๊ณ  ํ•  ๋•Œ, ํ•ด๋‹น ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ˆ˜์ • ์—†์ด ์ „๋žต ๊ตฌํ˜„์ฒด๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค.
  • ๋˜ํ•œ ์œ„์ž„์ด๋ผ๋Š” ์•ฝํ•œ ๊ฒฐํ•ฉ์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋‹ค์–‘ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„์ฒด๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹คํ–‰ ์ค‘ ๊ต์ฒด๋„ ๊ฐ€๋Šฅ

  • ํ•ด๋‹น ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ ๋™์ž‘ ์ค‘์—๋„ ์ „๋žต ๊ตฌํ˜„์ฒด๋ฅผ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ ์€ ํ™˜๊ฒฝ๊ณผ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋งŽ์€ ํ™˜๊ฒฝ์—์„œ ๋‹ค๋ฅธ ์ „๋žต์„ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๋‹ค์–‘ํ•œ ๋‚œ์ˆ˜ ์ƒ์„ฑ๊ธฐ

java.util.Random
  • ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋ฉฐ ์„ ํ˜•ํ•ฉ๋™๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค.ย 
  • Thread Safeํ•˜๋‹ค๋Š” ํŠน์ง•์ด ์žˆ์ง€๋งŒ,ย ThreadLocalRandomย ์ชฝ์ด ๋” ๊ณ ์„ฑ๋Šฅ์ด๊ณ , ๋ณด์•ˆ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค.
java.util.concurrent.ThreadLocalRandom
  • ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋„ ๊ณ ์„ฑ๋Šฅ์ด๋ฉฐ, ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค.
  • ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ณด์•ˆ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค.
java.security.SecureRandom
  • ์•”ํ˜ธํ•™์ ์œผ๋กœ ๊ฐ•ํ•œ ๋‚œ์ˆ˜ ์ƒ์„ฑ๊ธฐ๋กœ, ๋ณด์•ˆ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋œ๋‹ค.ย 
  • Thread Safeํ•˜๋‹ค.
This post is licensed under CC BY 4.0 by the author.