您的位置:首页 > 编程语言 > Java开发

图解设计模式 - Strategy 模式

2017-12-08 21:48 246 查看
读书笔记 仅供参考

策略模式

策略模式就是可以整体地替换算法,可以轻松地以不同的算法去解决同一个问题。

角色和 UML

Strategy

负责决定实现策略(算法)哦接口(API)

ConcreteStrategy

负责实现 Strategy 定义的接口(API)

Context

负责使用 Strategy 角色

UML



例子

例程是一个猜拳的程序,有两种猜拳策略,一是上一局赢了就不变手,输了就随机出,二是根据之前所有的出拳结果统计概率出拳。

//出拳手势
public class Hand {
public static final int HANDVALUE_GUU = 0;//代表石头
public static final int HANDVALUE_CHO = 1;//代表剪刀
public static final int HANDVALUE_PAA = 2;//代表步

public static final Hand[] hand = {
new Hand(HANDVALUE_GUU),
new Hand(HANDVALUE_CHO),
new Hand(HANDVALUE_PAA)
};

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 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;
}
}

@Override
public String toString() {
return name[handValue];
}
}


public interface Strategy {
Hand nextHand();
//根据上一局输赢进行学习
void study(boolean win);
}


public class WinningStrategy implements Strategy {
//如果上一局获胜,就和上一局出相同的
//如果上一局失败,随机出

//随机值,决定怎么出
private Random random;
//上一局的结果
private boolean won = false;
//上一局的手势
private Hand prevHand;

public WinningStrategy(int  seed) {
this.random = new Random(seed);
}

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

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


public class ProbStrategy implements Strategy {
//根据之前的猜拳结果概率决定

private Random random;
private int prevHandValue = 0;
private int currentHandValue = 0;

//history[上一局出的手势][这一局可能出的手势] 代表胜利的次数
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][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 = 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]++;
}
}
}


//选手,有姓名,策略,统计输赢
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 +
'}';
}
}


public class Main {

//生成两个选手,采取不同的策略
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int seed1 = scanner.nextInt();
int seed2 = scanner.nextInt();
Player player1 = new Player("Taro", new WinningStrategy(seed1));
Player player2 = new Player("Hana", 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("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());
}
}


UML



PS

策略模式使动态替换成为了可能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息