当前位置: 首页 > news >正文

策略模式实战 - 猜拳游戏

**可以整体的替换一套算法,这就是策略模式。**这样对于同一个问题,可以有多种解决方案——算法实现的时候,可以通过策略模式来非常方便的进行算法的整体替换,而各种算法是独立封装好的,不用修改其内部逻辑。

具体的实战,下面给出一个经典案例——“猜拳游戏”。该示例来自于【日】结城浩的《图解设计模式》,策略算法做了一些简化调整。

“石头剪刀布”的游戏每轮出什么样的手势,可以遵循一定的策略。比如可以按照下面两种策略来出手势:

  1. 看上一轮自己出的手势,如果赢了,继续用上一轮出的手势;否则出任意的手势
  2. 看上一轮对方出的手势
    1. 如果赢了,就出和上一轮不一样的手势;
    2. 如果上一轮平了(比如出的剪刀),本轮就出石头;
    3. 如果上一轮输了,本轮就出上一轮和对方一样的手势

文章目录

    • 整体类图设计
    • 出手势策略接口
    • 手势类
    • 玩家类
    • 策略实现类
    • 测试类

整体类图设计

在这里插入图片描述

出手势策略接口

因此抽象出一个出手势的策略接口:

/*** 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,由它负责设置和切换策略并调用策略的行为。

该玩家类除了namestrategy属性外,还包含了全局的状态信息(比赛总轮数、胜的轮数、败的轮数)。另外提供了调用策略对象完成出手势的方法以及对一轮比赛结果处理的方法。

在这里插入图片描述

策略实现类

正如前面一开始介绍的出手势的两种实现策略,这里提供两种具体的实现:

/*** 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);}}

程序输出:

在这里插入图片描述

相关文章:

策略模式实战 - 猜拳游戏

**可以整体的替换一套算法&#xff0c;这就是策略模式。**这样对于同一个问题&#xff0c;可以有多种解决方案——算法实现的时候&#xff0c;可以通过策略模式来非常方便的进行算法的整体替换&#xff0c;而各种算法是独立封装好的&#xff0c;不用修改其内部逻辑。 具体的实…...

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 模式介绍 你可能会发现&#xff0c;简单工厂模式没在经典设计模式里出现&#xff0c;别急&#xff0c;它其实只是个常用的编程技巧&#xff0c;而不是标准的设计模式。简单工厂模式有三个要素&#xff1a;1个产品接口、n个产品类、1个工厂类&#xff0c;工厂类通过if/else来…...

基于 AutoFlow 快速搭建基于 TiDB 向量搜索的本地知识库问答机器人

导读 本文将详细介绍如何通过 PingCAP 开源项目 AutoFlow 实现快速搭建基于 TiDB 的本地知识库问答机器人。如果提前准备好 Docker、TiDB 环境&#xff0c;整个搭建过程估计在 10 分钟左右即可完成&#xff0c;无须开发任何代码。 文中使用一篇 TiDB 文档作为本地数据源作为示…...

C语言学习:速通指针(2)

这里要学习的有以下内容 1. const修饰指针 2. 野指针 3. assert断⾔ 4. 指针的使⽤和传址调⽤ 那么从这里开始 1. const 修饰指针 const修饰变量 首先我们知道变量是可以修改的&#xff0c;如果把变量的地址交给⼀个指针变量&#xff0c;通过指针变量的也可以修改这个变…...

windows 上ffmpeg编译好的版本选择

1. Gyan.dev Gyan.dev 是一个广受信赖的 FFmpeg 预编译库提供者&#xff0c;提供多种版本的 FFmpeg&#xff0c;包括静态和动态链接版本。 下载链接: https://www.gyan.dev/ffmpeg/builds/ 特点&#xff1a; 提供最新稳定版和开发版。 支持静态和共享&#xff08;动态&…...

Java设计模式笔记(二)

十四、模版方法模式 1、介绍 1&#xff09;模板方法模式(Template Method Pattern)&#xff0c;又叫模板模式(Template Patern)&#xff0c;在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需重写方法实现&#xff0c;但调用将以抽象类中定义的方式进行。 2&…...

Vue CLI的作用

Vue CLI&#xff08;Command Line Interface&#xff09;是一个基于Vue.js的官方脚手架工具&#xff0c;其主要作用是帮助开发者快速搭建Vue项目的基础结构和开发环境。以下是Vue CLI的具体作用&#xff1a; 1、项目模板与快速生成 Vue CLI提供了一系列预设的项目模板&#x…...

短视频矩阵系统开发|技术源代码部署

短视频矩阵系统通过多账号运营管理、多平台视频智能分发等功能&#xff0c;助力企业实现视频引流、粉丝沉淀和转化。 短视频矩阵系统是一种创新的营销工具&#xff0c;它整合了多账号管理、视频智能分发、数据可视化等多种功能&#xff0c;为企业在短视频领域的发展提供了强大…...

Erlang socket编程(二)

模拟服务器和客户端通信 %%%------------------------------------------------------------------- %%% author Administrator %%% copyright (C) 2024, <COMPANY> %%% doc %%% %%% end %%% Created : 03. 12月 2024 22:28 %%%---------------------------------------…...

工业检测基础-线扫相机和面阵相机参数及应用

以下是工业面阵相机和线扫相机的重要参数、应用场景以及调节方法的科普&#xff1a; 重要参数 分辨率&#xff1a; 面阵相机&#xff1a;由相机所采用的芯片分辨率决定&#xff0c;常用的有500万、1200万、6500万等像素&#xff0c;一般用长宽表示。如19201080等&#xff0c;…...

【无标题】建议用坚果云直接同步zotero,其他方法已经过时,容易出现bug

created: 2024-12-06T16:07:45 (UTC 08:00) tags: [] source: https://zotero-chinese.com/user-guide/sync author: 数据与文件的同步 | Zotero 中文社区 Excerpt Zotero 中文社区&#xff0c;Zotero 中文维护小组&#xff0c;Zotero 插件&#xff0c;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 利用缓冲如何将一个点缓冲成一个方形

&#xff1a; 在Cesium中如果你想要一个更简单的方法将一个点缓冲成一个方形区域&#xff0c;你可以考虑以下步骤&#xff1a; 确定中心点&#xff1a;首先&#xff0c;你需要有一个中心点的经纬度坐标。计算边长&#xff1a;确定你想要缓冲的方形的边长&#xff0c;这里以10…...

HarmonyOS 5.0应用开发——Ability与Page数据传递

【高心星出品】 文章目录 Ability与Page数据传递Page向Ability传递数据Ability向Page传递数据 Ability与Page数据传递 基于当前的应用模型&#xff0c;可以通过以下几种方式来实现UIAbility组件与UI之间的数据同步。 使用EventHub进行数据通信&#xff1a;在基类Context中提供…...

【推荐算法】推荐系统的评估

这篇文章是笔者阅读《深度学习推荐系统》第五章推荐系统的评估的学习笔记&#xff0c;在原文的基础上增加了自己的理解以及内容的补充&#xff0c;在未来的日子里会不断完善这篇文章的相关工作。 文章目录 离线评估划分数据集方法客观评价指标P-R曲线ROC/AUCmAPNDCG A/B 测试分…...

鸿蒙:实现类似Android.9图的图片资源呈现

问题&#xff1a; 在鸿蒙中&#xff0c;是识别不了.9格式的图片资源的&#xff0c;那么如何实现.9图效果呢。&#xff1f; 解决方案&#xff1a; 首先需要将图片资源转为普通的png格式。如果是背景图的&#xff0c;需要换一种方式来处理&#xff0c;目前我所实现的方案是通过St…...

ros2人脸检测

第一步&#xff1a; 首先在工作空间/src下创建数据结构目录service_interfaces ros2 pkg create service_interfaces --build-type ament_cmake 然后再创建一个srv目录 在里面创建FaceDetect.srv&#xff08;注意&#xff0c;首字母要大写&#xff09; sensor_msgs/Image …...

Pillow:强大的Python图像处理库

目录 一、引言 二、Pillow 库的安装 三、Pillow 库的基本概念 四、图像的读取和保存 五、图像的基本属性 六、图像的裁剪、缩放和旋转 七、图像的颜色调整 八、图像的滤镜效果 九、图像的合成和叠加 十、图像的绘制 十一、示例程序&#xff1a;制作图片水印 十二、…...

微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算

微信小程序uni-appvue3实现局部上下拉刷新和scroll-view动态高度计算 前言 在uni-appvue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...