策略模式实战 - 猜拳游戏
**可以整体的替换一套算法,这就是策略模式。**这样对于同一个问题,可以有多种解决方案——算法实现的时候,可以通过策略模式来非常方便的进行算法的整体替换,而各种算法是独立封装好的,不用修改其内部逻辑。
具体的实战,下面给出一个经典案例——“猜拳游戏”。该示例来自于【日】结城浩的《图解设计模式》,策略算法做了一些简化调整。
“石头剪刀布”的游戏每轮出什么样的手势,可以遵循一定的策略。比如可以按照下面两种策略来出手势:
- 看上一轮自己出的手势,如果赢了,继续用上一轮出的手势;否则出任意的手势
- 看上一轮对方出的手势
- 如果赢了,就出和上一轮不一样的手势;
- 如果上一轮平了(比如出的剪刀),本轮就出石头;
- 如果上一轮输了,本轮就出上一轮和对方一样的手势
文章目录
- 整体类图设计
- 出手势策略接口
- 手势类
- 玩家类
- 策略实现类
- 测试类
整体类图设计

出手势策略接口
因此抽象出一个出手势的策略接口:
/*** Java小卷带你轻松高效学编程,一对一辅导加q1372569394*/
package com.juan.java.designpattern.strategy;/**** @author Java小卷* @date 2024-12-04 14:16* @since 1.0*/
public interface Strategy {/*** 下一回合出手势的方法* @author Java小卷* @date 2024/12/5 14:04* @return 出的手势* @since 1.0*/Hand nextHand();/*** 仔细考虑上一轮的结果,作为下一轮出手势的策略的依据* @author Java小卷* @date 2024/12/5 14:07* @param result 上一轮的结果 0-打平 1-胜 -1-负* @param other 上一轮对方的手势* @since 1.0*/void study(int result, Hand other);}

手势类
封装了手势具体信息和比手势的方法。

这里会维护3个公开的静态常量来分别维护“石头、剪刀、布”的手势数值。
/** 出的石头 */
public static final int HANDVALUE_STONE = 0;
/** 出的剪刀 */
public static final int HANDVALUE_SCISSORS = 1;
/** 出的布 */
public static final int HANDVALUE_PAPER = 2;
为方便对三种手势对象的获取,这里的手势值和三种手势对象的数组的索引值保持一致。
在Hand类中维护一个私有的静态数组常量,初始化3个手势对象:
/** 初始化三种手势:石头、剪刀、布 */
private static final Hand[] HANDS = {new Hand(HANDVALUE_STONE),new Hand(HANDVALUE_SCISSORS),new Hand(HANDVALUE_PAPER)
};
同时维护一个对应手势名称的静态数组常量:
/** 描述出的手势的名称数组 */
private static final String[] HAND_NAMES = {"石头", "剪刀", "布"};
提供一个代表所出的手势值的成员变量,并提供相应的构造方法完成其初始化,注意Hand类不能在外部实例化,只能在内部维护,因此用private修饰:
/** 出的当前手势值 */
private final int handValue;/** 私有的带有手势值的构造 */
private Hand(int handValue) {this.handValue = handValue;
}
提供几个获取手势信息的方法:
/*** 根据手势值获取对应的手势对象* @param handValue 手势值* @return 对应的手势对象*/
public static Hand getHand(int handValue) {return HANDS[handValue];
}/*** 返回当前实例的手势名称* @author Java小卷* @date 2024/12/4 10:57* @return 手势名称* @since 1.0
*/
@Override
public String toString() {return HAND_NAMES[handValue];
}/*** 获取手势数值* @author Java小卷* @date 2024/12/5 15:14* @return int 手势数值* @since 1.0
*/
public int getHandValue() {return handValue;
}
提供比较手势的方法
/*** 手势对战方法* @author Java小卷* @date 2024/12/4 10:42* @param hand 对方出的手势* @return int 0-平局 1-胜 -1-负* @since 1.0
*/
private int fight(Hand hand) {// 自身比较无意义,但这里也记为平局if (this == hand) {return 0;} else if ((this.handValue + 1) % 3 == hand.handValue) {// 游戏规则:石头>剪刀>布>石头// 因此,只要按照数组的顺序,当前手势的下一个元素与对方手势相等,就认为自己赢了return 1;} else {// 其他情况都是判负return -1;}
}/*** 对外提供的判断赢了方法* @author Java小卷* @date 2024/12/4 10:55* @param hand 对方手势* @return boolean* @since 1.0
*/
public boolean isStrongThan(Hand hand) {return this.fight(hand) == 1;
}
玩家类
Player类在策略模式的类设计中,作为Context,由它负责设置和切换策略并调用策略的行为。
该玩家类除了name、strategy属性外,还包含了全局的状态信息(比赛总轮数、胜的轮数、败的轮数)。另外提供了调用策略对象完成出手势的方法以及对一轮比赛结果处理的方法。

策略实现类
正如前面一开始介绍的出手势的两种实现策略,这里提供两种具体的实现:
/*** Java小卷带你轻松高效学编程,一对一辅导加q1372569394*/
package com.juan.java.designpattern.strategy.impl;import .../**** @author Java小卷* @date 2024-12-04 14:21* @since 1.0*/
public class WinningStrategy implements Strategy {private final Random random;private int prevResult;private Hand prevHand;public WinningStrategy() {random = new Random();}@Overridepublic Hand nextHand() {// 前一轮不胜,则随意出if (prevResult != 1) {prevHand = Hand.getHand(random.nextInt(3));}// 否则出上一轮的手势return prevHand;}@Overridepublic void study(int result, Hand other) {this.prevResult = result;}
}
/*** Java小卷带你轻松高效学编程,一对一辅导加q1372569394*/
package com.juan.java.designpattern.strategy.impl;import .../**** @author Java小卷* @date 2024-12-04 15:38* @since 1.0*/
public class SmartStrategy implements Strategy {private final Random random;private int prevResult = 1;private Hand prevOtherHand;public SmartStrategy() {this.random = new Random();}@Overridepublic Hand nextHand() {// 如果前一轮平,则出比它大的if (prevResult == 0) {return Hand.getHand(Math.floorMod(prevOtherHand.getHandValue() - 1, 3));} else if (prevResult == -1) {// 输了则出和对方一样的return Hand.getHand(prevOtherHand.getHandValue());} else {// 赢了,则出不一样的if (prevOtherHand == null) {return Hand.getHand(random.nextInt(3));} else {Hand prevHand = Hand.getHand(Math.floorMod(prevOtherHand.getHandValue() - 1, 3));// 出和prevHand不一样的随机手势return Hand.getHand(Math.floorMod(prevHand.getHandValue() + random.nextInt(2) + 1, 3));}}}@Overridepublic void study(int result, Hand other) {this.prevResult = result;this.prevOtherHand = other;}
}
测试类
/*** Java小卷带你轻松高效学编程,一对一辅导加q1372569394*/
package com.juan.java.designpattern.strategy;import .../**** @author Java小卷* @date 2024-12-04 14:46* @since 1.0*/
public class Main {public static void main(String[] args) {Player player1 = new Player("糖宝", new WinningStrategy());Player player2 = new Player("小卷", new SmartStrategy());// 比赛10轮for (int i = 0; i < 10; i++) {Hand hand1 = player1.nextHand();Hand hand2 = player2.nextHand();if (hand1.isStrongThan(hand2)) {System.out.println("胜者: " + player1);player1.win(hand2);player2.lose(hand1);} else if (hand2.isStrongThan(hand1)) {System.out.println("胜者: " + player2);player2.win(hand1);player1.lose(hand2);} else {System.out.println("打平...");player1.even(hand2);player2.even(hand1);}}System.out.println("最终结果:");System.out.println(player1);System.out.println(player2);}}
程序输出:

相关文章:
策略模式实战 - 猜拳游戏
**可以整体的替换一套算法,这就是策略模式。**这样对于同一个问题,可以有多种解决方案——算法实现的时候,可以通过策略模式来非常方便的进行算法的整体替换,而各种算法是独立封装好的,不用修改其内部逻辑。 具体的实…...
AWS ECS Task 添加 Prometheus 监控采集配置详细指南
以下是一篇完整的博文,介绍如何在 AWS ECS 环境中实现 JVM 监控。 AWS ECS 环境下的 JVM 监控实践 概述 在 AWS ECS (Elastic Container Service) 环境中监控 Java 应用性能是一项重要任务。本文将详细介绍如何使用 AWS Distro for OpenTelemetry (ADOT) 结合 Spring Boot …...
5. 一分钟读懂“工厂方法模式”
5.1 模式介绍 你可能会发现,简单工厂模式没在经典设计模式里出现,别急,它其实只是个常用的编程技巧,而不是标准的设计模式。简单工厂模式有三个要素:1个产品接口、n个产品类、1个工厂类,工厂类通过if/else来…...
基于 AutoFlow 快速搭建基于 TiDB 向量搜索的本地知识库问答机器人
导读 本文将详细介绍如何通过 PingCAP 开源项目 AutoFlow 实现快速搭建基于 TiDB 的本地知识库问答机器人。如果提前准备好 Docker、TiDB 环境,整个搭建过程估计在 10 分钟左右即可完成,无须开发任何代码。 文中使用一篇 TiDB 文档作为本地数据源作为示…...
C语言学习:速通指针(2)
这里要学习的有以下内容 1. const修饰指针 2. 野指针 3. assert断⾔ 4. 指针的使⽤和传址调⽤ 那么从这里开始 1. const 修饰指针 const修饰变量 首先我们知道变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变…...
windows 上ffmpeg编译好的版本选择
1. Gyan.dev Gyan.dev 是一个广受信赖的 FFmpeg 预编译库提供者,提供多种版本的 FFmpeg,包括静态和动态链接版本。 下载链接: https://www.gyan.dev/ffmpeg/builds/ 特点: 提供最新稳定版和开发版。 支持静态和共享(动态&…...
Java设计模式笔记(二)
十四、模版方法模式 1、介绍 1)模板方法模式(Template Method Pattern),又叫模板模式(Template Patern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需重写方法实现,但调用将以抽象类中定义的方式进行。 2&…...
Vue CLI的作用
Vue CLI(Command Line Interface)是一个基于Vue.js的官方脚手架工具,其主要作用是帮助开发者快速搭建Vue项目的基础结构和开发环境。以下是Vue CLI的具体作用: 1、项目模板与快速生成 Vue CLI提供了一系列预设的项目模板&#x…...
短视频矩阵系统开发|技术源代码部署
短视频矩阵系统通过多账号运营管理、多平台视频智能分发等功能,助力企业实现视频引流、粉丝沉淀和转化。 短视频矩阵系统是一种创新的营销工具,它整合了多账号管理、视频智能分发、数据可视化等多种功能,为企业在短视频领域的发展提供了强大…...
Erlang socket编程(二)
模拟服务器和客户端通信 %%%------------------------------------------------------------------- %%% author Administrator %%% copyright (C) 2024, <COMPANY> %%% doc %%% %%% end %%% Created : 03. 12月 2024 22:28 %%%---------------------------------------…...
工业检测基础-线扫相机和面阵相机参数及应用
以下是工业面阵相机和线扫相机的重要参数、应用场景以及调节方法的科普: 重要参数 分辨率: 面阵相机:由相机所采用的芯片分辨率决定,常用的有500万、1200万、6500万等像素,一般用长宽表示。如19201080等,…...
【无标题】建议用坚果云直接同步zotero,其他方法已经过时,容易出现bug
created: 2024-12-06T16:07:45 (UTC 08:00) tags: [] source: https://zotero-chinese.com/user-guide/sync author: 数据与文件的同步 | Zotero 中文社区 Excerpt Zotero 中文社区,Zotero 中文维护小组,Zotero 插件,Zotero 中文 CSL 样式 数…...
基于STM32设计的智能宠物喂养系统(华为云IOT)_273
文章目录 一、前言1.1 项目介绍【1】项目开发背景【2】设计实现的功能【3】项目硬件模块组成【4】设计意义【5】国内外研究现状【6】摘要1.2 设计思路1.3 系统功能总结1.4 开发工具的选择【1】设备端开发【2】上位机开发1.5 参考文献1.6 系统框架图1.7 系统原理图1.8 实物图1.9…...
cesium truf 利用缓冲如何将一个点缓冲成一个方形
: 在Cesium中如果你想要一个更简单的方法将一个点缓冲成一个方形区域,你可以考虑以下步骤: 确定中心点:首先,你需要有一个中心点的经纬度坐标。计算边长:确定你想要缓冲的方形的边长,这里以10…...
HarmonyOS 5.0应用开发——Ability与Page数据传递
【高心星出品】 文章目录 Ability与Page数据传递Page向Ability传递数据Ability向Page传递数据 Ability与Page数据传递 基于当前的应用模型,可以通过以下几种方式来实现UIAbility组件与UI之间的数据同步。 使用EventHub进行数据通信:在基类Context中提供…...
【推荐算法】推荐系统的评估
这篇文章是笔者阅读《深度学习推荐系统》第五章推荐系统的评估的学习笔记,在原文的基础上增加了自己的理解以及内容的补充,在未来的日子里会不断完善这篇文章的相关工作。 文章目录 离线评估划分数据集方法客观评价指标P-R曲线ROC/AUCmAPNDCG A/B 测试分…...
鸿蒙:实现类似Android.9图的图片资源呈现
问题: 在鸿蒙中,是识别不了.9格式的图片资源的,那么如何实现.9图效果呢。? 解决方案: 首先需要将图片资源转为普通的png格式。如果是背景图的,需要换一种方式来处理,目前我所实现的方案是通过St…...
ros2人脸检测
第一步: 首先在工作空间/src下创建数据结构目录service_interfaces ros2 pkg create service_interfaces --build-type ament_cmake 然后再创建一个srv目录 在里面创建FaceDetect.srv(注意,首字母要大写) sensor_msgs/Image …...
Pillow:强大的Python图像处理库
目录 一、引言 二、Pillow 库的安装 三、Pillow 库的基本概念 四、图像的读取和保存 五、图像的基本属性 六、图像的裁剪、缩放和旋转 七、图像的颜色调整 八、图像的滤镜效果 九、图像的合成和叠加 十、图像的绘制 十一、示例程序:制作图片水印 十二、…...
微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算
微信小程序uni-appvue3实现局部上下拉刷新和scroll-view动态高度计算 前言 在uni-appvue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...
