๐ ใ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
ํ๋ค.