Strategy模式即策略模式,在编程中,策略指的就是算法。利用此模式可以整体替换算法,即使用不同方式解决同一个问题。比如设计一个围棋程序,通过切换算法可以方便地切换AI的难度。

示例程序

要实现:模拟两个人用不同的策略玩猜拳游戏。

UML

Hand类(手势类)

public class Hand {
public static final int HANDVALUE_ST = 0; // 表示石头的值
public static final int HANDVALUE_JD = 1; // 表示剪刀的值
public static final int HANDVALUE_BU = 2; // 表示布的值
public static final Hand[] hand = { // 表示猜拳中3种手势的实例
new Hand(HANDVALUE_ST),
new Hand(HANDVALUE_JD),
new Hand(HANDVALUE_BU),
};
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 h) { // 如果this胜了h则返回true
return fight(h) == 1;
} public boolean isWeakerThan(Hand h) { // 如果this输给了h则返回true
return fight(h) == -1;
} private int fight(Hand h) { // 计分:平0, 胜1, 负-1
if (this == h) {
return 0;
} else if ((this.handvalue + 1) % 3 == h.handvalue) {
return 1;
} else {
return -1;
}
} public String toString() { // 转换为手势值所对应的字符串
return name[handvalue];
}
}

Strategy接口

public interface Strategy {
//获取下一局要出的手势
public abstract Hand nextHand();
//如果win为true,表示上一局赢了,否则表示上一局输了
public abstract void study(boolean win);
}

WinningStrategy类

如果赢了就继续出同样的手势,否则换一个手势

public class WinningStrategy implements Strategy {
private Random random;
private boolean won = false;
private Hand prevHand; public WinningStrategy(int seed) {
random = new Random(seed);
} public Hand nextHand() {
if (!won) {
prevHand = Hand.getHand(random.nextInt(3));
}
return prevHand;
} public void study(boolean win) {
won = win;
}
}

ProbStrategy类

根据以前的结果计算概率,确定这一次要出什么手势。

算法的具体内容不是关键,我们只需要知道这是一种算法就行了。

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) {
random = new Random(seed);
}
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);
}
private int getSum(int hv) {
int sum = 0;
for (int i = 0; i < 3; i++) {
sum += history[hv][i];
}
return sum;
}
public void study(boolean win) {
if (win) {
history[prevHandValue][currentHandValue]++;
} else {
history[prevHandValue][(currentHandValue + 1) % 3]++;
history[prevHandValue][(currentHandValue + 2) % 3]++;
}
}
}

Player类(玩家类)

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" + "]";
}
}

测试类

public class Main {
public static void main(String[] args) {
int seed1 = Integer.parseInt("888");
int seed2 = Integer.parseInt("999");
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(具体的策略):具体的策略类,继承Strategy接口,实现其中的方法。

Context(上下文):使用策略类的角色。注意:Context类和Strategy类是聚合关系,或者说是委托关系。

模式的类图:

想法

这个模式的实现非常简单:Context使用委托这种弱关联关系,方便地实现算法的整体替换。

最新文章

  1. Web API系列(一)设计经验与总结
  2. codeforces 429E
  3. java攻城狮之路(Android篇)--MP3 MP4、拍照、国际化、样式主题、图片移动和缩放
  4. 用自己的机器人和ubuntu PC实现通信和控制--26
  5. Jquery实现购物车物品数量的加减特效
  6. tomcat服务器 去掉端口8080 以及项目名 直接使用IP地址访问
  7. java基础(十八)IO流(一)
  8. 【原创】CMD常用命令:解决实际问题
  9. Netty之心跳检测技术(四)
  10. bzoj 4871: [Shoi2017]摧毁“树状图” [树形DP]
  11. 深入理解内存映射mmap
  12. ASP.NET Core 2.0 新功能汇总
  13. 使用阿里云公网ip建立bind,监听客户端连接失败
  14. 2018.5.2 file结构体
  15. apache atlas资料收集
  16. Android Netty Server
  17. python 爬虫 ~ 查看收发包的情况
  18. mp4网页播放代码,有声音无图像的解决办法~
  19. Log4j配置概述
  20. javascript中类数组转成真正的数组

热门文章

  1. 《剑指offer》面试题19 二叉树的镜像 Java版
  2. 3.Golang的包导入
  3. P3379 【模板】最近公共祖先(LCA)(欧拉序+rmq)
  4. 什么是dockerfile?
  5. Untiy3D的游戏物体的实例和刚体的使用
  6. HashMap对象转换为JavaBean对象
  7. IC设计流程介绍
  8. Oracle Grid,ASM,Database on Redhat 7.5
  9. OpenVINO 安装及使用
  10. 阿里云轻应用云服务器配置tomcat