天天看點

設計模式(JAVA)——Strategy模式1. Strategy模式

1. Strategy模式

整體的替換算法或政策

1.1 Strategy模式的類圖

設計模式(JAVA)——Strategy模式1. Strategy模式

登場的角色:

  • Strategy(政策)

    決定實作政策所必需的接口(API)

  • ConcreteStrategy(具體的政策)

    實作了Strategy角色的接口

  • Context(上下文)

    Context角色儲存了ConcreteStrategy角色的執行個體,并使用了Strategy的接口。

1.2 示例程式

類一覽表:

名字 說明
Hand 猜拳遊戲中的“手勢”類
Strategy 猜拳遊戲中的政策接口
WinningStrategy 以“根據上一局猜拳獲勝,那麼下一局也出一樣的手勢”的政策實作類
ProbStratgey 以“根據上一局的手勢從機率上計算出下一局的手勢從之前的猜拳結果計算下一局出各種拳的機率”的政策實作類
Player 進行遊戲的選手類
Main 測試類

uml類圖(隻含繼承關系)

設計模式(JAVA)——Strategy模式1. Strategy模式

uml類圖

設計模式(JAVA)——Strategy模式1. Strategy模式

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《設計模式》和結城浩的《圖解設計模式》