@(设计模式)[设计模式, 策略模式, Stategy]
策略模式主要用于整体切换解决方案,算法。一般使用委托来实现。
package com.pc.strategy.example;
/**
* 猜拳手势类
* Created by Switch on 2017-02-20.
*/
public class Hand {
private static final int HANDVALUE_ST = 0; // 石头
private static final int HANDVALUE_JD = 1; // 剪刀
private static final int HANDVALUE_BU = 2; // 布
private int handValue; // 手势值
// 手势值对应的手势名
private static final String[] name = {
"石头", "剪刀", "布"
};
// 手势实例
public static final Hand[] hand = {
new Hand(HANDVALUE_ST),
new Hand(HANDVALUE_JD),
new Hand(HANDVALUE_BU)
};
/**
* 构造方法,私有化,不能new出实例,注册表单例模式
*
* @param handValue 手势值
*/
private Hand(int handValue) {
this.handValue = handValue;
}
/**
* 根据手势值,获取手势实例
*
* @param handValue 手势值
* @return 手势实例
*/
public static Hand getHand(int handValue) {
return hand[handValue];
}
/**
* 赢了返回true
*
* @param hand 手势实例
* @return
*/
public boolean isStrongerThan(Hand hand) {
return fight(hand) == 1;
}
/**
* 输了返回true
*
* @param hand 手势实例
* @return
*/
public boolean isWeakerThan(Hand hand) {
return fight(hand) == -1;
}
/**
* 比较
*
* @param hand 手势实例
* @return
*/
private int fight(Hand hand) {
if (this.handValue == hand.handValue) {
return 0; // 平
} else if ((this.handValue + 1) % 3 == hand.handValue) {
return 1; // 胜
} else {
return -1; // 负
}
}
@Override
public String toString() {
// 手势值对应的手势名
return name[this.handValue];
}
}
package com.pc.strategy.example;
/**
* 猜拳策略接口
* Created by Switch on 2017-02-20.
*/
public interface Strategy {
/**
* 下一个出拳手势
*
* @return 手势实例
*/
Hand nextHand();
/**
* 根据上一次猜拳是否获胜,决定下一次的猜拳手势
*
* @param win 是否获胜
*/
void study(boolean win);
}
package com.pc.strategy.example;
import java.util.Random;
/**
* Winning策略类
* Created by Switch on 2017-02-20.
*/
public class WinningStrategy implements Strategy {
private Random random; // 随机
private boolean won = false; // 上一把是否赢了
private Hand prevHand; // 上一把的手势对象
/**
* 构造方法,传入初始化随机seek
*
* @param seed 随机种子
*/
public WinningStrategy(int seed) {
this.random = new Random(seed);
}
@Override
public Hand nextHand() {
if (!this.won) {
this.prevHand = Hand.getHand(this.random.nextInt(3));
}
return this.prevHand;
}
@Override
public void study(boolean win) {
this.won = win;
}
}
package com.pc.strategy.example;
import java.util.Random;
/**
* Prob策略类
* Created by Switch on 2017-02-20.
*/
public class ProbStrategy implements Strategy {
private Random random; // 随机
private int prevHandValue; // 上一把的手势值
private int currentHandValue; // 这一把的手势值
// 历史出拳概率数组
// history[上一把的手势值][这一把的手势值] 表示赢的次数
private int[][] history = {
{1, 1, 1},
{1, 1, 1},
{1, 1, 1}
};
/**
* 构造方法,传入初始化随机seek
*
* @param seed 随机种子
*/
public ProbStrategy(int seed) {
this.random = new Random(seed);
}
@Override
public Hand nextHand() {
int randomValue = this.random.nextInt(this.getSum(this.currentHandValue));
int handValue = 0;
if (randomValue < this.history[this.currentHandValue][0]) {
// 当随机数在0到剪刀赢的次数时,赋值为0
handValue = 0;
} else if (randomValue < this.history[this.currentHandValue][0] + this.history[this.currentHandValue][1]) {
// 当随机数在剪刀赢的次数到石头赢得次数时,赋值为1
handValue = 1;
} else {
// 其他情况,赋值为2
handValue = 2;
}
// 当前值赋值为之前值
this.prevHandValue = this.currentHandValue;
// 计算出来的值赋值为当前值
this.currentHandValue = handValue;
return Hand.getHand(handValue);
}
/**
* 获取history[上一把的手势值][三种手势]赢的总次数
*
* @param hv 上一把的手势值
* @return history[上一把的手势值][三种手势]赢的总次数
*/
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[上一把的手势值][这一把的手势]赢的次数加一
this.history[this.prevHandValue][this.currentHandValue]++;
} else {
// history[上一把的手势值][其他手势]赢的次数加一
this.history[this.prevHandValue][(this.currentHandValue + 1) % 3]++;
this.history[this.prevHandValue][(this.currentHandValue + 2) % 3]++;
}
}
}
package com.pc.strategy.example;
/**
* 玩家类
* Created by Switch on 2017-02-20.
*/
public class Player {
private String name; // 玩家名
private Strategy strategy; // 策略对象
private int wincount; // 赢的次数
private int losecount; // 输出次数
private int gamecount; // 游戏总次数
/**
* 构造方法
*
* @param name 玩家名
* @param strategy 策略对象
*/
public Player(String name, Strategy strategy) {
this.name = name;
this.strategy = strategy;
}
/**
* 策略决定下次要出的手势
*
* @return 手势对象
*/
public Hand nextHand() {
return this.strategy.nextHand();
}
/**
* 赢
*/
public void win() {
this.strategy.study(true);
this.wincount++;
this.gamecount++;
}
/**
* 输
*/
public void lose() {
this.strategy.study(false);
this.losecount++;
this.gamecount++;
}
/**
* 平
*/
public void even() {
this.gamecount++;
}
@Override
public String toString() {
return "[" + this.name + ":" + this.gamecount + " games, " + this.wincount + " win, " + this.losecount + " lose]";
}
}
package com.pc.strategy.example.test;
import com.pc.strategy.example.Hand;
import com.pc.strategy.example.Player;
import com.pc.strategy.example.ProbStrategy;
import com.pc.strategy.example.WinningStrategy;
import org.junit.Test;
/**
* Strategy Tester.
*
* @author Switch
* @version 1.0
*/
public class StrategyTest {
/**
* 测试策略类
*/
@Test
public void testStrategy() {
Player switchvov = new Player("switch", new WinningStrategy(54));
Player kity = new Player("kity", new ProbStrategy(32));
for (int i = 0; i < 10000; i++) {
Hand nextValue1 = switchvov.nextHand();
Hand nextValue2 = kity.nextHand();
if (nextValue1.isStrongerThan(nextValue2)) {
switchvov.win();
kity.lose();
System.out.println("Winner:" + switchvov);
} else if (nextValue1.isWeakerThan(nextValue2)) {
switchvov.lose();
kity.win();
System.out.println("Winner:" + kity);
} else {
System.out.println("Even...");
switchvov.even();
kity.even();
}
}
System.out.println("Total Result:");
System.out.println(switchvov);
System.out.println(kity);
}
}
Winner:[switch:1 games, 1 win, 0 lose]
Winner:[switch:2 games, 2 win, 0 lose]
Even...
Winner:[kity:4 games, 1 win, 2 lose]
Winner:[kity:5 games, 2 win, 2 lose]
省略N行。。。
Winner:[switch:9998 games, 3136 win, 3642 lose]
Winner:[switch:9999 games, 3137 win, 3642 lose]
Winner:[kity:10000 games, 3643 win, 3137 lose]
Total Result:
[switch:10000 games, 3137 win, 3643 lose]
[kity:10000 games, 3643 win, 3137 lose]
Strategy
角色负责决定实现策略所必需的接口(API
)。在案例中,由Strategy
接口扮演此角色。
ConcreteStrategy
角色负责实现Strategy
角色的接口(API
) ,即负责实现具体的策略(战略、方向、方法和算法)。在案例中,由WinningStrategy
类和ProbStrategy
类扮演此角色。
负责使用Strategy
角色。Context
角色保存了ConcreteStrategy
角色的实例,并使用ConcreteStrategy
角色去实现需求(总之,还是要调用Strategy
角色的接口(API
))。在案例中,由Player
类扮演此角色。
GitHub:DesignPatternStudy
——————参考《图解设计模式》