1. Strategy模式
整體的替換算法或政策
1.1 Strategy模式的類圖
登場的角色:
-
Strategy(政策)
決定實作政策所必需的接口(API)
-
ConcreteStrategy(具體的政策)
實作了Strategy角色的接口
-
Context(上下文)
Context角色儲存了ConcreteStrategy角色的執行個體,并使用了Strategy的接口。
1.2 示例程式
類一覽表:
名字 | 說明 |
---|---|
Hand | 猜拳遊戲中的“手勢”類 |
Strategy | 猜拳遊戲中的政策接口 |
WinningStrategy | 以“根據上一局猜拳獲勝,那麼下一局也出一樣的手勢”的政策實作類 |
ProbStratgey | 以“根據上一局的手勢從機率上計算出下一局的手勢從之前的猜拳結果計算下一局出各種拳的機率”的政策實作類 |
Player | 進行遊戲的選手類 |
Main | 測試類 |
uml類圖(隻含繼承關系)
uml類圖
Hand類
package xin.ajay.strategy;
public enum Hand {
HANDVALUE_R("石頭", 0), HANDVALUE_S("剪刀", 1), HANDVALUE_P("布", 2);
private int value;
private String name;
private Hand(String name, int value) {
this.name = name;
this.value = value;
}
public static Hand getHand(int value) {
switch (value) {
case 0:
return Hand.HANDVALUE_R;
case 1:
return Hand.HANDVALUE_S;
case 2:
default:
return Hand.HANDVALUE_P;
}
}
//平 0,勝 1,負 -1
public int fight(Hand h) {
if (this == h) {
return 0;
} else if ((this.value + 1) % 3 == h.value) {
return 1;
} else {
return -1;
}
}
@Override
public String toString() {
return "Hand{" + "name='" + name + '\'' + '}';
}
}
Strategy接口
package xin.ajay.strategy;
public interface Strategy {
//出手的政策
Hand nextHand();
//根據輸赢進行學習
void study(boolean win);
}
Player類
package xin.ajay.strategy;
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 "Player{" + "name='" + name + '\'' + ", wincount=" + wincount + ", losecount=" + losecount + ", gamecount=" + gamecount + '}';
}
}
WinningStrategy類
package xin.ajay.strategy;
import java.util.Random;
public class WinningStrategy implements Strategy {
private Random random = new Random();
private boolean won = false;
private Hand prevHand;
@Override
public Hand nextHand() {
if(!won){
prevHand = Hand.getHand(random.nextInt(3));
}
return prevHand;
}
@Override
public void study(boolean win) {
won = win;
}
}
ProbStratgey類
package xin.ajay.strategy;
import java.util.Random;
public class ProbStrategy implements Strategy {
private Random random = new Random();
private int prevHandValue = 0;
private int currentHandValue = 0;
//history[上局手勢][這一局手勢] 勝利的次數
private int[][] history = new int[][]{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}};
@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;
prevHandValue = handvalue;
return Hand.getHand(handvalue);
}
private int getSum(int hv){
int sum = 0;
for (int i = 0; i < 3; i++) {
sum +=history[hv][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]++;
}
}
}
Main類
package xin.ajay.strategy;
public class Main {
public static void main(String[] args) {
Player a = new Player("A", new WinningStrategy());
Player b = new Player("B", new ProbStrategy());
for (int i = 0; i < 10; i++) {
Hand hand = a.nextHand();
Hand hand1 = b.nextHand();
switch (hand.fight(hand1)){
case 0:
System.out.println("Winner:"+a);a.win();b.lose();break;
case -1:
System.out.println("Winner:"+b);a.lose();b.win();break;
case 1:
System.out.println("Even..");a.even();b.even();break;
}
}
System.out.println("Total result:");
System.out.println(a.toString());
System.out.println(b.toString());
}
}
鳴謝
GoF《設計模式》和結城浩的《圖解設計模式》