1. Strategy模式
整体的替换算法或策略
1.1 Strategy模式的类图
登场的角色:
-
Strategy(策略)
决定实现策略所必需的接口(API) -
ConcreteStrategy(具体的策略)
实现了Strategy角色的接口 -
Context(上下文)
Context角色保存了ConcreteStrategy角色的实例,并使用了Strategy的接口。
1.2 示例程序
类一览表:
名字 | 说明 |
---|---|
Hand | 猜拳游戏中的“手势”类 |
Strategy | 猜拳游戏中的策略接口 |
WinningStrategy | 以“根据上一局猜拳获胜,那么下一局也出一样的手势”的策略实现类 |
ProbStratgey | 以“根据上一局的手势从概率上计算出下一局的手势从之前的猜拳结果计算下一局出各种拳的概率”的策略实现类 |
Player | 进行游戏的选手类 |
Main | 测试类 |
uml类图(只含继承关系)
uml类图
Hand类
package xin.ajay.strategy;
public enum Hand {
HANDVALUE_R("石头", 0), HANDVALUE_S("剪刀", 1), HANDVALUE_P("布", 2);
private int value;
private String name;
private Hand(String name, int value) {
this.name = name;
this.value = value;
}
public static Hand getHand(int value) {
switch (value) {
case 0:
return Hand.HANDVALUE_R;
case 1:
return Hand.HANDVALUE_S;
case 2:
default:
return Hand.HANDVALUE_P;
}
}
//平 0,胜 1,负 -1
public int fight(Hand h) {
if (this == h) {
return 0;
} else if ((this.value + 1) % 3 == h.value) {
return 1;
} else {
return -1;
}
}
@Override
public String toString() {
return "Hand{" + "name='" + name + '\'' + '}';
}
}
Strategy接口
package xin.ajay.strategy;
public interface Strategy {
//出手的策略
Hand nextHand();
//根据输赢进行学习
void study(boolean win);
}
Player类
package xin.ajay.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 + '\'' + ", wincount=" + wincount + ", losecount=" + losecount + ", gamecount=" + gamecount + '}';
}
}
WinningStrategy类
package xin.ajay.strategy;
import java.util.Random;
public class WinningStrategy implements Strategy {
private Random random = new Random();
private boolean won = false;
private Hand prevHand;
@Override
public Hand nextHand() {
if(!won){
prevHand = Hand.getHand(random.nextInt(3));
}
return prevHand;
}
@Override
public void study(boolean win) {
won = win;
}
}
ProbStratgey类
package xin.ajay.strategy;
import java.util.Random;
public class ProbStrategy implements Strategy {
private Random random = new Random();
private int prevHandValue = 0;
private int currentHandValue = 0;
//history[上局手势][这一局手势] 胜利的次数
private int[][] history = new int[][]{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}};
@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;
prevHandValue = 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]++;
}
}
}
Main类
package xin.ajay.strategy;
public class Main {
public static void main(String[] args) {
Player a = new Player("A", new WinningStrategy());
Player b = new Player("B", new ProbStrategy());
for (int i = 0; i < 10; i++) {
Hand hand = a.nextHand();
Hand hand1 = b.nextHand();
switch (hand.fight(hand1)){
case 0:
System.out.println("Winner:"+a);a.win();b.lose();break;
case -1:
System.out.println("Winner:"+b);a.lose();b.win();break;
case 1:
System.out.println("Even..");a.even();b.even();break;
}
}
System.out.println("Total result:");
System.out.println(a.toString());
System.out.println(b.toString());
}
}
鸣谢
GoF《设计模式》和结城浩的《图解设计模式》