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使用委托这种弱关联关系,方便地实现算法的整体替换。

《图解设计模式》读书笔记4-2 STRATEGY模式的更多相关文章

  1. HeadFirst设计模式读书笔记(3)-装饰者模式(Decorator Pattern)

    装饰者模式:动态地将责任附件到对象上.若要扩展功能,装饰者提东了比继承更有弹性的替代方案. 装饰者和被装饰对象有相同的超类型 你可以用一个或者多个装饰者包装一个对象. 既然装饰者和被装饰对象有相同的超 ...

  2. HeadFirst设计模式读书笔记--目录

    HeadFirst设计模式读书笔记(1)-策略模式(Strategy Pattern) HeadFirst设计模式读书笔记(2)-观察者模式(Observer Pattern) HeadFirst设计 ...

  3. Head First 设计模式读书笔记(1)-策略模式

    一.策略模式的定义 策略模式定义了算法族,分别封装起来,让它们之间可以互换替换,此模式让算法的变化独立使用算法的客户. 二.使用策略模式的一个例子 2.1引出问题 某公司做了一套模拟鸭子的游戏:该游戏 ...

  4. C#设计模式学习笔记:(19)策略模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8057654.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第七个模式--策 ...

  5. JavaScript设计模式:读书笔记(未完)

    该篇随我读书的进度持续更新阅读书目:<JavaScript设计模式> 2016/3/30 2016/3/31 2016/4/8 2016/3/30: 模式是一种可复用的解决方案,可用于解决 ...

  6. Head First设计模式读书笔记

    阅读指南: 精读一章内容,手工输入一章代码(注1),与书中描述的思想进行印证,实在搞不懂就放过吧.设计模式绝对不会一次就看懂的. 这本书对于理解设计模式很有帮助,就是例子不太符合中国人的思维模式,但是 ...

  7. 图解http读书笔记

    以前对HTTP协议一知半解,一直不清楚前端需要对于HTTP了解到什么程度,知道接触的东西多了,对于性能优化.服务端的配合和学习中也渐渐了解到了HTTP基础的重要性,看了一些大神对HTTP书籍的推荐,也 ...

  8. Java设计模式学习笔记(二) 简单工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...

  9. Java设计模式学习笔记(三) 工厂方法模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...

  10. Java设计模式学习笔记(四) 抽象工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...

随机推荐

  1. MongoDB查询系统

    首先,我们先向集合(collections)中添加测试文档(documents).如下: > for(i=1;i<=5;i++) db.test.insert({x:i,y:i*i,z:6 ...

  2. Maven-maven安装、Eclipse配置maven

    1.下载maven安装包,下载完成,解压到安装路径. 2.配置环境变量 3.修改setting.xml配置本地库,阿里云中央仓库 路径:C:\fyliu\software\apache-maven-3 ...

  3. Golang环境配置

    下载 下载地址 Go官网下载地址:https://golang.org/dl/ Go官方镜像站(推荐):https://golang.google.cn/dl/ 版本选择 安装 Windows安装 示 ...

  4. P4643 [国家集训队]阿狸和桃子的游戏

    传送门 这题看一眼就很不可做 考虑对于任意一个最终状态,对于一条边的贡献分成三种情况 如果此边连接的两点属于 $A$,那么对 $A$ 的贡献就是边权 $w$,即对答案的贡献为 $+w$ 如果两点都属于 ...

  5. UVAlive 3485 Bridge(抛物线弧长积分)

    Bridge A suspension bridge suspends the roadway from huge main cables, which extend from one end of ...

  6. 文本框的pattern属性

    代码实例: test.html <!DOCTYPE html><html lang="en"><head> <meta charset=& ...

  7. linux环境进程开机自检脚本

    Linux下shell脚本监控Tomcat的状态并实现自动启动 最近公司需要在Linux下监控tomcat的服务,一旦tomcat服务存在异常或者宕机,重启tomcat保证服务的正常运行,由于Linu ...

  8. flask之jinjia2模板

    一:渲染模板 app.run(debug=True)  开启debug模式,flask框架自动提示错误提示的页面显示. 视图函数 from flask import Flask from flask ...

  9. hdu 6035:Colorful Tree (2017 多校第一场 1003) 【树形dp】

    题目链接 单独考虑每一种颜色,答案就是对于每种颜色至少经过一次这种的路径条数之和.反过来思考只需要求有多少条路径没有经过这种颜色即可. 具体实现过程比较复杂,很神奇的一个树形dp,下面给出一个含较详细 ...

  10. proxyTable-后端代理-跨域请求数据

    config >>> index.js  配置 proxyTable: { '/api': { target:'https://api.jisuapi.com', // 你请求的第三 ...