以不同的算法去解决同一个问题的模式是Strategy模式,Strategy模式可以整体地替换算法的实现部分。
一、示例程序
“猜拳游戏”
两种策略:1.如果这局猜拳获胜,那么下一局也出一样手势;2.根据上一局的手势从概率上计算出下一局的手势
Hand类:
package Strategy;
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 isStrongThan(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];
}
}
Hand类表示猜拳游戏中的手势的类,在该类的内部,0-石头、1-剪刀、2-布
开始时创建三个实例,包括石头剪刀布三个实例,保存在数组中。判断猜拳结果的是isStrongThan方法和isWeakThan方法,实际负责判断猜拳结果的是fight方法。
Strategy接口:
package Strategy;
//算法接口,抽象方法,在实现该接口的类中必须实现这些方法
public interface Strategy {
public abstract Hand nextHand();
public abstract void study(boolean win);
}
该接口定义了猜拳策略的抽象方法,nextHand方法的作用是获取下一局要出的手势,study方法是学习上一局是否胜利了,如果调用了nextHand方法获胜了就调用study(true),如果失败了就调用study(false)
WinningStrategy类:
package Strategy;
import java.util.Random;
//实现抽象接口的具体类
public class WinningStrategy implements Strategy {
private Random random;
private boolean won = false;
private Hand prevHand;
//初始时随机
public WinningStrategy(int seed) {
// TODO Auto-generated constructor stub
random = new Random(seed);
}
//如果上一局输了,则这句随机出,如果赢了,继续出上一句的策略
@Override
public Hand nextHand() {
// TODO Auto-generated method stub
if(!won){
prevHand = Hand.getHand(random.nextInt(3));
}
return prevHand;
}
//获取上一局是赢了还是输了
@Override
public void study(boolean win) {
// TODO Auto-generated method stub
won = win;
}
}
接口的实现类,won字段保留上一局的结果,prevHand保留上一局的手势
ProbStrategy类
package 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 seed) {
// TODO Auto-generated constructor stub
random = new Random(seed);
}
@Override
public Hand nextHand() {
// TODO Auto-generated method stub
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);
}
private int getSum(int hv) {
// TODO Auto-generated method stub
int sum = 0;
for(int i = 0;i<3;i++){
sum += history[hv][i];
}
return sum;
}
@Override
public void study(boolean win) {
// TODO Auto-generated method stub
//如果赢了当前算法权重增加,如果输了另外的算法权重增加
if(win){
history[prevHandValue][currentHandValue]++;
}else{
history[prevHandValue][(currentHandValue+1)%3]++;
history[prevHandValue][(currentHandValue+2)%3]++;
}
}
}
另外一个具体的策略类
Player类:
package 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 Strategy;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
if(args.length!=2){
System.out.println("Usage:java Main randomseed1 randomseed2");
System.out.println("Example:java Main 314 15");
System.exit(0);
}
int seed1 = Integer.parseInt(args[0]);
int seed2 = Integer.parseInt(args[1]);
Player player1 = new Player("Taro",new WinningStrategy(seed1));
Player player2 = new Player("Hana",new WinningStrategy(seed2));
for (int i = 0; i<1000;i++){
Hand nextHand1 = player1.nextHand();
Hand nextHand2 = player2.nextHand();
if(nextHand1.isStrongThan(nextHand2))
{
System.out.println("Winner:"+player1);
player1.win();
player2.lose();
}else if(nextHand1.isWeakerThan(nextHand2)){
System.out.println("Winner:"+player2);
player2.win();
player1.lose();
}else{
System.out.println("Even...");
player1.even();
player2.even();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Total result:");
System.out.println(player1.toString());
System.out.println(player2.toString());
}
}
注:使用委托这种弱关联关系可以很方便的替换整个算法。