一天一個設計模式——Strategy策略模式

1、模式說明java

  策略模式比較好理解,就是將程序中用到的算法總體的拿出來,並有多個不一樣版本的算法實現,在程序運行階段,動態的決定使用哪一個算法來解決問題。算法

  舉個實際的例子:排序算法的問題,假如咱們的程序中須要對數據進行排序,咱們知道,不一樣的算法具備不一樣的時間複雜度和空間複雜度,所以須要在程序運行時,根據可用內存和數據特徵,選用不一樣的算法(排序策略),這就是策略模式的使用場景之一。再舉個例子,負載均衡算法:若是某個服務部署了多個冗餘的實例,客戶端在向服務端發送請求時,根據負載均衡算法策略,請求可能會被轉發到不一樣的服務提供者實例來處理,如何決定某個請求轉發給哪一個服務實例呢,最簡單的作法就是輪詢,順次將請求轉發給每一個服務實例進行處理。也能夠採用隨機方式,或者根據實際硬件環境和業務場景設置特定算法。設計模式

2、模式類圖負載均衡

3、程序示例dom

  在下面的演示策略模式的代碼示例中,咱們模擬猜拳遊戲——剪刀石頭布,猜拳的策略有兩種:若是此次猜拳贏了,則下次還出一樣的手勢。另外一種策略就是根據之前的猜拳結果,選擇勝率最高的一種手勢。ide

一、Hand類:表示猜拳遊戲中的手勢,並不是Strategy策略模式中的角色。this

package com.designpattern.cn.strategypattern;

public class Hand {
    public static final int HANDVALUE_ROCK = 0; //表示石頭
    public static final int HANDVALUE_SCISSORS = 1; //表示剪刀
    public static final int HANDVALUE_PEPER = 2; //表示布
    private static final Hand[] hand = {
            new Hand(HANDVALUE_ROCK),
            new Hand(HANDVALUE_SCISSORS),
            new Hand(HANDVALUE_PEPER)
    };
    private static final String[] name = {
            "石頭", "剪刀", "布"
    };
    private int handValue;
    private Hand(int handValue){
        this.handValue = handValue;
    }
    public static Hand getHand(int handValue){
        return hand[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;
        }
    }
    public String toString(){
        return name[handValue];
    }
}
View Code

二、Strategy接口:spa

package com.designpattern.cn.strategypattern;

public interface Strategy {
    public abstract Hand nextHand();
    public abstract void study(boolean win);
}
View Code

三、WinningStrategy類:設計

package com.designpattern.cn.strategypattern;

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);
    }
    public Hand nextHand(){
        if(!won){
            prevHand = Hand.getHand(random.nextInt(3));
        }
        return prevHand;
    }
    public void study(boolean win){
        won = win;
    }
}
View Code

四、ProbStrategy類:3d

package com.designpattern.cn.strategypattern;

import java.util.Random;

public class ProbStrategy implements Strategy {
    private Random random;
    private int prevHandValue = 0;
    private int currentHandValue = 0;
    //history[上一局的手勢][這一局的手勢] 表達式的值越高表示過去的勝率越高
    //study方法會根據nextHand方法返回的手勢勝負結果更新history字段中的值
    private int[][] history = {
            {1, 1, 1},
            {1, 1, 1},
            {1, 1, 1}
    };

    public ProbStrategy(int seed) {
        random = new Random(seed);
    }

    public Hand nextHand() {
        int bet = random.nextInt(getSum(currentHandValue));
        int handValue = 0;
        if (bet < history[currentHandValue][0]) {
            handValue = 0;
        }else if(bet < history[currentHandValue][1]){
        handValue = 1;
        }else{
            handValue = 2;
        }
        prevHandValue = currentHandValue;
        currentHandValue = handValue;
        return Hand.getHand(handValue);
    }
    private int getSum(int hv){
        int sum = 0;
        for (int i : history[hv]
             ) {
            sum += i;
        }
        return sum;
    }
    public void study(boolean win){
        if(win){
            history[prevHandValue][currentHandValue]++;
        }else{
            history[prevHandValue][(currentHandValue+1)%3]++;
            history[prevHandValue][(currentHandValue+2)%3]++;
        }
    }
}
View Code

五、Player類:

package com.designpattern.cn.strategypattern;

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" + "]";
    }
}
View Code

六、Main類與運行結果:

package com.designpattern.cn.strategypattern;

import java.util.Random;

public class Main {
    public static void main(String[] args){
        int seed1 = ((new Random()).nextInt(500))*(1+(new Random()).nextInt(500));
        int seed2 = seed1 * (new Random()).nextInt(500);

        Player player1 = new Player("Taro", new WinningStrategy(seed1));
        Player player2 = new Player("Hana", new ProbStrategy(seed2));
        for(int i = 0; i < 100000; 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);
                player2.win();
                player1.lose();
            }else{
                System.out.println("Even...");
                player1.even();
                player2.even();
            }
        }
        System.out.println("Total result:");
        System.out.println(player1.toString());
        System.out.println(player2.toString());
    }
}
View Code

4、Strategy策略模式中的角色

  • Strategy策略:負責定義實現策略必須的接口方法
  • ConcreteStrategy具體的策略:實現Strategy角色的接口,如程序中的WinningStrategy和ProbStrategy
  • Context上下文:負責使用Strategy策略,如示例程序中的player。

5、相關的設計模式

  • Flyweight享元模式:經過使用享元模式,讓多個地方共用ConcreteStrategy角色;
  • Abstract Factory抽象工廠:策略模式總體替換算法,抽象工廠總體替換具體的工廠,零件和產品;
  • State狀態模式:狀態模式和策略模式均可以替換被委託對象,並且類之間的關係也類似,只是兩種模式目的不一樣。strategy策略模式替換被委託對象的類;狀態模式中,每次狀態發生變化時,被委託的對象一定會被替換。
相關文章
相關標籤/搜索