GOF設計模式——Strategy模式

1、什麼是Strategy模式?java

        Strategy,意思是「策略」的意思。使用Strategy模式設計的代碼,就自帶一種邏輯判斷在裏面,能夠總體的替換算法的實現部分,或者說跟機器學習有類似之處。算法

2、Strategy模式思想數組

Context類:裏面定義了Strategy類型屬性,負責使用Strategy接口,使用了委託,其實是調用Strategy的實現類的具體方法;dom

Strategy接口:負責決定實現策略所必須的接口;機器學習

ConcreteStrategy類:實現了Strategy接口的策略方法。ide

3、Strategy模式示例學習

        這裏有一個猜拳遊戲,如今設定有兩種出拳策略,第一種是「若是這局猜拳獲勝,那麼下一局也出一樣的手勢」;第二種是「根據上一次的手勢機率計算下一局的手勢」。this

UML圖:spa

一、Hand類:Hand類並非Strategy模式的角色,這裏只是爲了方便,特地編寫了一個表示「手勢」的類,使用final和static修飾的int類型表示所出的手勢,其中0表示石頭,1表示剪刀,2表示布,並將值保存在handvalue裏面。isStrongerTha和isWeakerThan用於判斷猜拳的結果。設計

package com.cjs.Strategy; public class Hand { private final static int HANDVALUE_GUU = 0; private final static int HANDVALUE_CHO = 1; private final static int HANDVALUE_PAA = 2; private int handvalue; private Hand(int handvalue) { this.handvalue = handvalue; } public static Hand getHand(int handvalue) { return hand[handvalue]; } private static final Hand[] hand = {new Hand(HANDVALUE_CHO), new Hand(HANDVALUE_GUU), new Hand(HANDVALUE_PAA)}; private final static String[] name = {"石頭", "剪刀", "布"}; public boolean isStrongerThan(Hand hand) { return fight(hand) == 1; } public boolean isWeakerThan(Hand hand) { return fight(hand) == -1; } private int fight(Hand hand) { if (this == hand) { return 0; } else if ((this.handvalue + 1) % 3 == hand.handvalue) { return 1; } else { return -1; } } public String toString() { return name[handvalue]; } }

二、Strategy接口:定義了猜拳的抽象方法的接口,newtHand用於獲取下一局要出的手勢,study方法是學習「上一局的手勢是否獲勝」。

package com.cjs.Strategy; public interface Strategy { public abstract Hand nextHand(); public abstract void study(boolean win); }

三、WinningStrategy類:實現了Strategy接口,這個類設定是屬於猜拳的第一種策略,就是若是這局贏了,下一局就繼續使用一樣的手勢。

package com.cjs.Strategy; import java.util.Random; public class WinningStrategy implements Strategy { private Random random; private boolean won = false; private Hand preHand; public WinningStrategy(int seed) { this.random = new Random(seed); } @Override public Hand nextHand() { //若是上一局輸了,就隨機出拳
        if (!won) { preHand = Hand.getHand(random.nextInt(3)); } return preHand; } @Override public void study(boolean win) { won = win; } }

四、ProbStrategy類:實現了Strategy接口,這個類設定是屬於第二種策略,會根據以前猜拳的出拳機率來決定i下一局應該使用哪種手勢。

package com.cjs.Strategy; import java.util.Random; public class ProbStrategy implements Strategy { private Random random; private int preHandValue = 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; } //當前手勢「變成」上一局手勢
        preHandValue = currentHandValue; //計算後手勢「變成」當前手勢
        currentHandValue = handvalue; return Hand.getHand(handvalue); } @Override public void study(boolean win) { if (win) { history[preHandValue][currentHandValue]++; } else { //若是沒有獲勝,意味着其餘兩種手勢的獲勝次數要+1
            history[preHandValue][(currentHandValue+1)%3]++; history[preHandValue][(currentHandValue+2)%3]++; } } //計算基於上一局手勢時的三種手勢勝出次數總和
    public int getSum(int hv) { int sum = 0; for (int i = 0; i < 3; i++) { sum += history[hv][i]; } return sum; } }

        history[][]字段是一個表,用於根據過去的勝負來計算機率,它是一個二維數組,每一個元素能夠表示爲:history[上一局的手勢][下一局的手勢]。假設上一局出的是石頭,用0去表示,則上一局出拳頭的history有三種可能,分別是history[0][0],history[0][1]和history[0][2],每一個值表明勝出次數:兩局都出石頭時勝出的次數,兩局分別出石頭、剪刀時勝出的次數和兩局分別出石頭、布時勝出的次數。

        假如history[0][0]=3,history[0][1]=5,history[0][2]=7,下一局出石頭、剪刀和布的機率比就是3:5:7。

五、Player類:表示進行猜拳遊戲的選手類。

package com.cjs.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++; } public String toString() { return "[" + name + ":" + gameCount + " games, " + winCount + " win, " + loseCount + " lose " + "]"; } }

六、Main類

package com.cjs.Strategy; import java.util.Random; public class Main { public static void main(String[] args) { Random random = new Random(System.currentTimeMillis()); int seed1 = random.nextInt(3); int seed2 = random.nextInt(3); Player player1 = new Player("Tony", new WinningStrategy(seed1)); Player player2 = new Player("Jimmy", new ProbStrategy(seed2)); for (int i = 0; i < 500; i++) { Hand nextHand1 = player1.nextHand(); Hand nextHand2 = player2.nextHand(); if (nextHand1.isStrongerThan(nextHand2)) { System.out.println("Winner is : " + player1); player1.win(); player2.lose(); } else if (nextHand1.isWeakerThan(nextHand2)) { System.out.println("Winner is : " + player2); player1.lose(); player2.win(); } else { System.out.println("Even ... "); player1.even(); player2.even(); } } System.out.println("Total result: "); System.out.println(player1.toString()); System.out.println(player2.toString()); } }

運行屢次,會有不一樣的結果出現,輸出結果:

4、Strategy模式的優勢

        貌似使用Strategy模式會使得程序變得複雜,其實否則。例如,當咱們想要通改善算法來提升算法 的處理速度時,若是使用了Strategy模式,就沒必要要修改Strategy角色的接口,僅僅修改ConcreteStrategy角色類的實現便可。並且,使用委託這種弱關聯關係,使得總體替換算法更加方便。在不少遊戲裏面選擇關卡難度時,就是選擇不一樣的AI策略。

相關文章
相關標籤/搜索