中奖记录设计(策略+模板)

背景

        最近需求要做一个活动需求,用户只要参与活动就可以获得奖励,奖励分为以下几种:

创角奖励: 用户在活动内的游戏创建角色即可中奖

等级奖励: 角色在游戏内级别达到某一个级别即可中奖

VIP级别奖励: 角色在游戏内VIP级别达到某一个级别即可中奖

排行榜奖励: 角色某一天充值榜一即可中奖

       

        如果按照传统的做法,就是每种中奖内部去进行判断逻辑,比如角色是没有啥条件的,等级是需要达到指定的等级,VIP需要达到指定的VIP级别等

        可能代码中就会存在大量的判断逻辑,而且前置逻辑都差不多,所以才会考虑用设计模式来进行处理

具体实现

设计图

代码逻辑实现

接口

public interface RebateActivityRecordHandler {RebateActivityRecordHandlerVo handler(Long userRoleId);RebateActivityPrizeSendTypeEnum getRebatePrizeSendType();
}

抽象类(核心)

@Slf4j
public abstract class AbstractRebateActivityRecordHandler implements RebateActivityRecordHandler{@Resourceprivate IRebateActivityAttendUserService rebateActivityAttendUserService;@Resource@Lazyprivate IRebateActivityRoleRecordService rebateActivityRoleRecordService;@Resourceprivate UserRoleService userRoleService;@Overridepublic RebateActivityRecordHandlerVo handler(Long userRoleId) {RebateActivityRecordHandlerVo handlerVo = new RebateActivityRecordHandlerVo();UserRole userRole = userRoleService.getUserRole(userRoleId);if(userRole == null) {log.info("id为{}的角色不存在", userRoleId);return handlerVo;}//获取角色参与了哪个活动RebateActivityAttendUser rebateActivityAttendUser = rebateActivityAttendUserService.queryByRoleId(userRoleId);if(rebateActivityAttendUser == null) {log.info("roleId为 {} 没有参与任何一个活动,直接返回", userRoleId);return handlerVo;}//角色在某个活动内关联的数据List<RebateActivityRoleRecord> rebateActivityRoleRecordList = rebateActivityRoleRecordService.queryList(rebateActivityAttendUser.getRebateActivityId(), doGetRebatePrizeSendType(), userRoleId, userRole.getAppNumber());//调用模板方法进行真正的校验处理等return doHandler(userRole, rebateActivityAttendUser, rebateActivityRoleRecordList);}@Overridepublic RebatePrizeSendTypeEnum getRebatePrizeSendType() {return doGetRebatePrizeSendType();}protected abstract RebatePrizeSendTypeEnum doGetRebatePrizeSendType();protected abstract RebateActivityRecordHandlerVo doHandler(UserRole userRole, RebateActivityAttendUser rebateActivityAttendUser, List<RebateActivityRoleRecord> rebateActivityRoleRecordList);
}

主要就是doHandler方法,下面看下其中一个实现类

创角奖励

@Service
@Slf4j
public class RebateActivityCreateRoleRecordHandler extends AbstractRebateActivityRecordHandler {@Overrideprotected RebatePrizeSendTypeEnum doGetRebatePrizeSendType() {return RebatePrizeSendTypeEnum.CREATE_ROLE;}@Overrideprotected RebateActivityRecordHandlerVo doHandler(UserRole userRole, RebateActivityAttendUser rebateActivityAttendUser, List<RebateActivityRoleRecord> rebateActivityRoleRecordList) {RebateActivityRecordHandlerVo recordHandlerVo = new RebateActivityRecordHandlerVo();if(rebateActivityRoleRecordList.size() >= RebateActivityGameConst.RECORD_COUNT) {log.info("活动创角奖励只能有 {} 个, 角色id为{}, 活动id为{}, 超出了直接返回", RebateActivityGameConst.RECORD_COUNT, userRole.getId(),null);return recordHandlerVo;}//创角奖励目前只有这个校验,如有其他的再加入RebateActivityRoleRecord rebateActivityRoleRecord = buildBaseRecord(userRole, rebateActivityAttendUser);recordHandlerVo.setSuccess(true);recordHandlerVo.setNeedSaveList(Collections.singletonList(rebateActivityRoleRecord));return recordHandlerVo;}
}

实现自己所需要的逻辑即可,其他的几种也是类似的,最后还有个上下文,如下

上下文

@Slf4j
@Component
public class RebateActivityRecordHandlerContext implements InitializingBean {@Resourceprivate List<RebateActivityRecordHandler> recordHandlerList;private Map<RebatePrizeSendTypeEnum, RebateActivityRecordHandler> recordHandlerMap;@Overridepublic void afterPropertiesSet() throws Exception {recordHandlerMap = new ConcurrentHashMap<>();RebatePrizeSendTypeEnum[] sendTypeEnums = RebatePrizeSendTypeEnum.values();for (RebatePrizeSendTypeEnum sendTypeEnum : sendTypeEnums) {recordHandlerMap.put(sendTypeEnum, query(sendTypeEnum));}}private RebateActivityRecordHandler query(RebatePrizeSendTypeEnum prizeSendType) {for (RebateActivityRecordHandler rebateActivityRecordHandler : recordHandlerList) {if(Objects.equals(rebateActivityRecordHandler.getRebatePrizeSendType(), prizeSendType)) {return rebateActivityRecordHandler;}}throw new IllegalArgumentException("类型为 " + prizeSendType.getDesc() + " 没有处理类,请参考RebatePrizeSendTypeEnum");}private RebateActivityRecordHandler assertHandler(RebatePrizeSendTypeEnum prizeSendType) {RebateActivityRecordHandler recordHandler = recordHandlerMap.get(prizeSendType);if(recordHandler == null) {throw new AppException(ErrorCode.SYS_ERROR.code(), "找不到活动中奖类型的处理类,类型为" + prizeSendType.getDesc());}return recordHandler;}public RebateActivityRecordHandlerVo handleRebateActivityRecord(Long userRoleId, RebatePrizeSendTypeEnum prizeSendType) {return assertHandler(prizeSendType).handler(userRoleId);}
}

注:这个类其实也可以不要,只是习惯性会用这么个东西,而且利用了spring的初始化方法来判断是否所有奖励类型都有对应的处理类,还是有意义的

备注:这个设计跟我另一篇文章很类似,如下,状态模式的

活动功能->状态模式的使用_活动状态模式代码-CSDN博客

总结

        主要采用的就是策略模式+模板模式,意义分别体现在

模板模式:  把基本的校验信息,比如活动是不是存在,角色是不是存在,角色是不是有参与某个活动逻辑都放在AbstractRebateActivityRecordHandler类中进行处理,这样的好处是其他几种中奖时前置判断条件就被统一了,假设以后要调整可以统一调整即可

策略模式: 把每种中奖逻辑单独用类封装起来,自己去实现要过滤的逻辑相互不影响,也更容易找到对应的地方进行修改,后续如果有其他的中奖记录根据这种类型添加实现类即可

整体来说,好处就是逻辑解耦了,但是代码量多了,而且没有研究过设计模式的可能一时半会看不太懂是什么意思

模式对比

       

状态模式: 也就是当前的模式, 每种策略都必须实现接口的方法,因为只是实现不同

状态模式: 参考我上面的文章,它跟策略模式很像,但是还是有区别的,每种状态不一定会实现所有方法,比如结束状态的实现类就是个空实现,因为他不能切换为任何一种状态

这是两者间一个很明显的对比,而且状态模式肯定是有很多方法不需要实现的,状态切换是有一定的规则的

        

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

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

相关文章

Qt+Vs踩坑之QString转std::string中文乱码

文章目录 1.Qt内部的编码造成的中文乱码2.QString与std::string之间转换造成的中文乱码3.QString、string、char*之间的转换4.参考文献 Qt中字符串存在两种中文乱码的情况&#xff1a;1.Qt内部的编码造成的中文乱码&#xff1b;2.QString与std::string之间转换造成的中文乱码。…

nodejs连接mongodb报错SyntaxError: Unexpected token .

nodejs连接mongodb报错SyntaxError: Unexpected token 如下图 经过排查&#xff0c;原因是npm默认安装的mongodb插件是最新版6.3.0 &#xff0c;而mongodb数据库版本是4.0.0 &#xff0c;两者版本不同导致nodejs报错。 解决方法是npm卸载新版本的mongodb插件&#xff0c;再安…

【Java探索之旅】我与Java的初相识(二):程序结构与运行关系和JDK,JRE,JVM的关系

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java入门到精通 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. 第一个Java程序1.1 main方法1.2 Java的程序结构 二. Java程序的运行三. JDK、JR…

【YOLOV8追踪篇】使用Ultralytics YOLO进行物体追踪

YOLOV8追踪 目录 一 使用已训练的检测模型进行追踪 二 其他 视频分析领域的物体追踪是一项关键的任务,既能够标识出帧内物体的位置和类别,还能在视频进行的过程中为每个检测到的物体保持一个唯一的ID(追踪)。 Ultralytics YOLOv8相关介绍:

Achronix提供由FPGA赋能的智能网卡(SmartNIC)解决方案来打破智能网络性能极限

作者&#xff1a;Achronix 随着人工智能/机器学习&#xff08;AI/ML&#xff09;和其他复杂的、以数据为中心的工作负载被广泛部署&#xff0c;市场对高性能计算的需求持续飙升&#xff0c;对高性能网络的需求也呈指数级增长。高性能计算曾经是超级计算机这样一个孤立的领域&a…

20 Vue3中使用v-for遍历普通数组

概述 使用v-for遍历普通数组在真实开发中还是比较常见的。 基本用法 我们创建src/components/Demo20.vue&#xff0c;代码如下&#xff1a; <script setup> const tags ["JavaScript", "Vue3", "前端"] </script> <template…

301_C++_字符串解析函数‘strcasestr‘

if ((pctmpA = strcasestr(const_cast<char *>(pcMsg), "MotionAlarm"))&& (pctmpA =

(1)(1.10) SiK Radio v1

文章目录 前言 1 概述 2 连接无线电台 3 参数说明 前言 本文介绍了如何将 3DR Radio v1 连接到飞行控制器。你还应阅读 SiK Radio v2&#xff0c;其中包含更详细的用户指南和功能列表。 1 概述 3DR 无线电设备是在自动驾驶仪和地面站之间建立遥测连接的最简单方法。 3DR…

uniapp怎么跳转页面

在 UniApp 中&#xff0c;你可以使用以下方法来跳转到其他页面&#xff1a; 使用<navigator>标签&#xff1a; <navigator url"/pages/example/example">点击跳转</navigator> 在上面的示例中&#xff0c;点击"点击跳转"会导航到/pag…

Redis高可用性方案:主从复制与哨兵机制详解

大家好&#xff0c;我是升仔 在高可用性数据服务的构建中&#xff0c;Redis扮演着重要的角色。Redis的主从复制和哨兵机制是实现高可用性的关键组件。本文将详细探讨这两种机制的使用场景、配置细节&#xff08;尤其是持久化配置&#xff09;&#xff0c;并讨论相应的异常处理…

常见加解密算法分析(含使用场景)

加密算法主要分为三类&#xff1a;对称加密算法、非对称加密算法和散列算法。下面将分别介绍这些类别中的常见算法及其特点和使用场景。 对称加密算法 1. AES (Advanced Encryption Standard) AES是一种广泛使用的对称加密标准&#xff0c;可以使用128、192和256位的密钥长度…

如何在Android Framework源码中增加jni方法

我们都知道&#xff0c;在Android Framework源码中&#xff0c;有很多这种类型的方法&#xff0c;方法前缀有"public static native",这种方法就是native方法&#xff0c;会调用到jni中去。 如&#xff1a;public static native long getNativeHeapSize(); 那如何在…

Golang实践录:gin绑定解析json的两种方法

本文介绍 Golang 的 gin 框架接收json数据并解析的2种方法。 起因及排查 某微服务工程&#xff0c;最近测试发现请求超时&#xff0c;由于特殊原因超时较短&#xff0c;如果请求处理耗时超过1秒则认为失败。排查发现&#xff0c;可能是gin接收解析json数据存在耗时&#xff0c…

大数据---34.HBase数据结构

一、HBase简介 HBase是一个开源的、分布式的、版本化的NoSQL数据库&#xff08;即非关系型数据库&#xff09;&#xff0c;依托Hadoop分布式文件系统HDFS提供分布式数据存储&#xff0c;利用MapReduce来处理海量数据&#xff0c;用Zookeeper作为其分布式协同服务&#xff0c;一…

逆波兰计算器的完整代码

前置知识&#xff1a; 将中缀表达式转为List方法&#xff1a; //将一个中缀表达式转成中缀表达式的List//即&#xff1a;(3042)*5-6 》[(, 30, , 42, ), *, 5, -, 6]public static List<String> toIndixExpressionList(String s) {//定义一个List&#xff0c;存放中缀表达…

R语言——基本操作(二)

目录 一、矩阵与数组 二、列表 三、数据框 四、因子 五、缺失数据 六、字符串 七、日期和时间 参考 一、矩阵与数组 matrix&#xff1a;创建矩阵&#xff0c;nrow 和 ncol 可以省略&#xff0c;但其值必须满足分配条件&#xff0c;否则会报错 只写一个值则自动分配&…

5. 创建型模式 - 单例模式

亦称&#xff1a; 单件模式、Singleton 意图 单例模式是一种创建型设计模式&#xff0c; 让你能够保证一个类只有一个实例&#xff0c; 并提供一个访问该实例的全局节点。 问题 单例模式同时解决了两个问题&#xff0c; 所以违反了单一职责原则&#xff1a; 保证一个类只有一…

人工智能在现代科技中的应用和未来发展趋势。

&#x1f431; 个人主页&#xff1a;SHOW科技&#xff0c;公众号&#xff1a;SHOW科技 &#x1f64b;‍♂️ 作者简介&#xff1a;2020参加工作&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;优质专栏&#x…

xtu oj 1394 单调

单调 题目描述 n∑ki0ai⋅bi,b≥2&#xff0c;如果i>0时&#xff0c;ai>ai−1&#xff0c;那么我们称这个数n是在b进制下是单调的。比如6,在3进制下为20(3)&#xff0c;所以6在3进制下是单调的。现在已知n&#xff0c;求最小的基b&#xff0c;使得n是单调的。 输入 第一…

谷歌Gemini造假始末

&#x1f4a1;大家好&#xff0c;我是可夫小子&#xff0c;《小白玩转ChatGPT》专栏作者&#xff0c;关注AIGC、读书和自媒体。 在过去一年中&#xff0c;OpenAI ChatGPT引发了一股AI新浪潮&#xff0c;而谷歌则一直处于被压制的状态&#xff0c;迫切需要一款现象级的AI产品来…