【java学习笔记】设计模式10——Strategy(策略)模式

 该文章是阅读《图解设计模式》的学习笔记。书本链接https://www.ituring.com.cn/book/1811

Strategy模式的作用是可以整体地替换算法的实现部分,让编程者轻松地以不同算法解决同一个问题。下面以猜拳游戏分两种猜拳策略为例,来说明Strategy模式,先来看类结构图:

 Hand类代码(用于标识猜拳游戏中的手势):

package com.wen.Strategy;

public class Hand {
    public static final int SHITOU = 0;
    public static final int JIANDAO = 1;
    public static final int BU = 2;
    public static final Hand[] hand = {
            new Hand(SHITOU),
            new Hand(JIANDAO),
            new Hand(BU),
    };

    private static final String[] name ={
      "石头","剪刀","布",
    };

    private int handValue;

    public Hand(int handValue) {
        this.handValue = handValue;
    }

    //根据手势获取对应的Hand实例
    public static Hand getHand(int handValue) {
        return hand[handValue];
    }

    private int fight(Hand hand){//计分方法,平局0分,赢了1分,输了-1分
        if(this == hand){
            return 0;
            //当前的值加1取余3,如当前值是布,布+1(即2+1)取余3是石头,布赢石头;其它情况同理
        }else if((this.handValue +1) % 3 == hand.handValue){
            return 1;
        }else{
            return -1;
        }
    }

    public boolean isStrongerThan(Hand hand){
        return fight(hand) == 1;
    }

    public boolean isWeakerThan(Hand hand){
        return fight(hand) == -1;
    }

    @Override
    public String toString() {
        return "Hand{" +
                "handValue=" + handValue +
                '}';
    }
}

Strategy类代码:

package com.wen.Strategy;

public interface Strategy {
    public abstract Hand nextHand();
    public abstract void study(boolean win);
}
ProbStrategy类代码:
package com.wen.Strategy;

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 range){
        random = new Random(range);
    }
    @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);
    }

    @Override
    public void study(boolean win) {
        if(win){
            history[prevHandValue][currentHandValue]++;
        }else{
            history[prevHandValue][(currentHandValue+1)%3]++;
            history[prevHandValue][(currentHandValue+2)%3]++;
        }
    }

    private int getSum(int handValue){
        int sum = 0;
        for(int i=0;i<3;i++){
            sum+=history[handValue][i];
        }
        return sum;
    }

}

WinningStrategy类代码:

package com.wen.Strategy;

import java.util.Random;

public class WinningStrategy implements Strategy {
    private Random random;
    private boolean win = false;

    private Hand nextHand;
    public WinningStrategy(int range){
        random = new Random(range);
    }

    @Override
    public Hand nextHand() {
        if(!win){
            nextHand = Hand.getHand(random.nextInt(3));
        }
        return nextHand;
    }

    @Override
    public void study(boolean win) {
        this.win = win;
    }
}

Player类代码:

package com.wen.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 + '\'' +
                ", gamecount=" + gamecount +
                ", wincount=" + wincount +
                ", losecount=" + losecount +
                '}';
    }
}

Main入口类代码:

package com.wen.Strategy;

public class Main {
    public static void main(String[] args) {
        int seed1 = 123;
        int seed2 = 456;
        Player player1 = new Player("小明", new WinningStrategy(seed1));
        Player player2 = new Player("小红", 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("胜利者:" + player1);
                player1.win();
                player2.lose();
            } else if (nextHand2.isStrongerThan(nextHand1)) {
                System.out.println("胜利者:" + player2);
                player1.lose();
                player2.win();
            } else {
                System.out.println("平局...");
                player1.even();
                player2.even();
            }
        }
        System.out.println("最终结果:");
        System.out.println(player1.toString());
        System.out.println(player2.toString());
    }
}

程序运行结果:

分析该模式中的角色: 

Strategy(策略) :负责定义实现策略所必需的方法接口。

ConcreteStrategy(具体的策略):负责实现策略角色中定义的接口方法。

Context(上下文):该角色负责使用Strategy角色里面定义了接口方法,并保存了ConcreteStrategy(具体的策略)角色的实例去使用具体的需求。

可扩展性:

编写了Strategy角色,在需要替换算法策略时,只需要修改ConcreteStrategy角色即可,在Player类中使用调用Strategy类实例这种委托的弱关联关系可以更方便地整体替换策略算法。如:编写棋牌类游戏程序时,使用Strategy模式可以更方便地根据选择切换AI的难度。

发布了54 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/baidu_35800355/article/details/105427154