策略模式实战 - 猜拳游戏

news2025/1/17 1:01:18

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

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

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

  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();
    }

    @Override
    public Hand nextHand() {
        // 前一轮不胜,则随意出
        if (prevResult != 1) {
            prevHand = Hand.getHand(random.nextInt(3));
        }
        // 否则出上一轮的手势
        return prevHand;
    }

    @Override
    public 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();
    }

    @Override
    public 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));
            }
        }
    }

    @Override
    public 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);
    }

}

程序输出:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2256479.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中建海龙:科技创新引领建筑业革新,铸就行业影响力

在建筑业这个古老而又充满活力的行业中&#xff0c;中建海龙科技有限公司&#xff08;以下简称“中建海龙”&#xff09;凭借其卓越的科技实力和一系列荣誉奖项&#xff0c;正逐步确立其在建筑工业化领域的领导地位&#xff0c;并对整个行业产生了深远影响。 中建海龙自成立以来…

混合云策略在安全领域受到青睐

Genetec 发布了《2025 年物理安全状况报告》&#xff0c;该报告根据超过 5,600 名该领域领导者&#xff08;其中包括 100 多名来自澳大利亚和新西兰的领导者&#xff09;的回应&#xff0c;揭示了物理安全运营的趋势。 报告发现&#xff0c;澳大利亚和新西兰的组织采用混合云策…

小程序 —— Day1

组件 — view和scroll-view view 类似于HTML中的div&#xff0c;是一个块级元素 案例&#xff1a;通过view组件实现页面的基础布局 scroll-view 可滚动的视图区域&#xff0c;用来实现滚动列表效果 案例&#xff1a;实现纵向滚动效果 scroll-x属性&#xff1a;允许横向滚动…

DemoFusion 技术浅析(四):跳跃残差

跳跃残差模块&#xff08;Skip Residual Module&#xff09; 是 DemoFusion 框架中用于图像去噪和细节保留的核心组件。该模块通过引入跳跃连接&#xff08;skip connections&#xff09;和残差学习&#xff08;residual learning&#xff09;&#xff0c;在图像去噪过程中有效…

电机功率、电压与电流的换算方法

在电气工程和相关行业中&#xff0c;电机的功率、电压和电流是三个重要的基本参数。它们之间有着密切的关系&#xff0c;而理解这些关系对于电机的选型、设计和应用至关重要。本文将详细阐述这三者之间的换算关系&#xff0c;以及相关公式的应用。 一、电机功率的定义 电机功…

k8s 之 Deployment

&#xff08;1&#xff09;Deployment 作用是确保 Pod 副本数量&#xff0c;能够保证 Pod 数量与期望值一样&#xff0c;会有自恢复功能。简洁地说&#xff1a;具有 水平扩展 / 收缩 功能。 可能好奇的是在 kubernetes 中是谁在执行这些控制器的&#xff0c;它就是 kube-contr…

浅谈FRTC8563M实时时钟芯片

FRTC8563M是NYFEA徕飞公司推出的一款实时时钟芯片和日历芯片&#xff0c;采用MSOP-8封装形式。它具有低功耗特性&#xff0c;适用于电池供电的便携式设备。该芯片提供年、月、日、星期、小时、分钟和秒的计时功能&#xff0c;并且具有闹钟功能。FRTC8563M通过I2C总线与微控制器…

SpringBoot 主导家乡特色推荐系统升级,无缝对接多元数据源

2系统相关技术 2.1 Java技术 Java是由SUN公司推出&#xff0c;该公司于2010年被oracle公司收购。Java本是印度尼西亚的一个叫做爪洼岛的英文名称&#xff0c;也因此得来java是一杯正冒着热气咖啡的标识。Java语言在移动互联网的大背景下具备了显著的优势和广阔的前景&#xff0…

Flink如何基于数据版本使用最新离线数据

业务场景 假设批量有一张商户表&#xff0c;表字段中有商户名称和商户分类两个字段。 批量需要将最新的商户名称和分类的映射关系推到hbase供实时使用。 原实现方案 a.原方案内容 为解决批量晚批问题&#xff0c;批量推送hbase表时一份数据产生两类rowkey&#xff1a;T-1和…

【集群划分】含分布式光伏的配电网集群电压控制【33节点】

目录 主要内容 模型研究 1.节点电压灵敏度的计算 2.Kmeans聚类划分 3.集群K值 部分代码 运行结果 下载链接 主要内容 该程序参考文献《含分布式光伏的配电网集群划分和集群电压协调控制》&#xff0c;基于社团检测算法&#xff0c;实现基于电气距离和区域电压调节能…

Elasticsearch 单节点安全配置与用户认证

Elasticsearch 单节点安全配置与用户认证 安全扫描时发现了一个高危漏洞&#xff1a;Elasticsearch 未授权访问 。在使用 Elasticsearch 构建搜索引擎或处理大规模数据时&#xff0c;需要启用基本的安全功能来防止未经授权的访问。本文将通过简单的配置步骤&#xff0c;为单节…

Docker打包SpringBoot项目

一、项目打成jar包 在进行docker打包之前&#xff0c;先确定一下&#xff0c;项目能够正常的打成JAR包&#xff0c;并且启动之后能够正常的访问。这一步看似是可有可无&#xff0c;但是能避免后期的一些无厘头问题。 二、Dockerfile 项目打包成功之后&#xff0c;需要编写Doc…

用OpenCV改变图像的对比度和亮度

两个常用的函数是常数的乘法和加法&#xff1a; 参数α>0和β通常被称为增益和偏置参数&#xff1b;有时这些参数分别控制对比度和亮度。 你可以想到f(x)作为源图像像素和g(x)作为输出图像像素。那么&#xff0c;更方便的是&#xff0c;我们可以将表达式写为&#xff1a; 这…

基于阻塞队列的生产者消费者模型动画演示

一个基于阻塞队列的生产者消费者模型的动画演示&#xff1a; 这是打包好的程序。程序是用 QT 写的。 通过网盘分享的文件&#xff1a;CP模型.7z 链接: https://pan.baidu.com/s/1YjC7YiSqHGqdr6bbffaDWg?pwde6g5 提取码: e6g5 CP模型

李沐动手学深度学习无法动态绘制损失和准确率曲线,输出 <Figure size 350x250 with 1 Axes>

在网上搜了两个解决方案 1.这个方法我试了不好用 d2l.plt.savefig(E:\pycharmProject) 2 修改封装好的函数 &#xff0c;ctrl加鼠标左键点击进入Animator类&#xff0c;修改里面的add函数 def add(self, x, y):# Add multiple data points into the figureif not hasattr(y,…

在idea中使用mysql(超详细)

一、连接mysql 在IDE开发工具中也是可以使用mysql的&#xff0c;这里以开发java常用的IntelliJ IDEA为例。 1. 打开idea&#xff0c;右上角有数据库侧边栏&#xff0c;打开侧边栏点击加号->数据源&#xff0c;可以看到支持很多数据库&#xff0c;选择mysql。 2. 首次使用需…

scss文件内引入其他scss文件报错

1、今天在编译一些老项目的时候&#xff0c;老是提示下面信息 2、而且有很多Sass import rules are deprecated and will be removed in Dart Sass 3.0.0.警告 3、用npm view sass versions看&#xff0c;其中sass的最新版本是1.82.0 4、经过测试"sass": "1.75…

【Linux】基础IO-----文件详解

目录 一、文件理解&#xff1a; 二、C语言的文件操作&#xff1a; 1、fopen&#xff1a; 什么是当前路径&#xff1a; 2、fclose&#xff1a; 3、fwrite&#xff1a; 4、默认打开的三个流&#xff1a; 三、系统文件&#xff1a; 1、open&#xff1a; 2、close&#xf…

AI开发:卷积神经网络CNN原理初识,简易例程 - 机器学习

一 、卷积神经网络是什么 &#xff08;1&#xff09;印象 今天说的CNN&#xff0c;并不是我们熟知的美国有线电视新闻网。 那什么是CNN呢&#xff1f; Convolutional Neural Networks, CNN&#xff09;简单来说&#xff0c;就是用一个筛子来筛面粉的。 筛子就是卷积核&…

Nginx基础学习——介绍、安装与常用命令(windows/linux安装详细攻略)

目录 前言&#xff1a; 一、 Nginx 基本概念 &#xff08;1&#xff09; Nginx 是什么&#xff0c; 做什么事情 &#xff08;2&#xff09; 反向代理 &#xff08;3&#xff09; 负载均衡 &#xff08;4&#xff09; 动静分离​编辑 二、 Nginx安装、常用命令和配置文件…