设计模式之策略模式例题:根据用户等级算积分的接口

问题

问题:写一个根据游戏用户等级来送赠送积分的方法接口,一共有100个等级,每种等级都有一个方法,使用策略模式。
在设计一个根据游戏用户等级来赠送积分的接口时,我们需要考虑几个关键点:

解决

性能:对于大量用户或频繁的操作,接口应该能够高效地处理请求。
可扩展性:随着游戏的更新或新的等级系统引入,接口应该能够容易地扩展。
易读性和维护性:代码应该清晰、易于理解,并易于维护。

基于上述考虑,以下使用策略模式

策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。策略模式使得算法可以独立于使用它的客户变化。对于这个问题,我们可以为每一个等级定义一个赠送积分的策略。这样,当我们需要改变某个等级的积分赠送规则时,我们只需要修改那个等级的策略,而不需要修改整个接口。

python 示例代码:

首先,定义一个策略接口:

from abc import ABC, abstractmethodclass RewardStrategy(ABC):@abstractmethoddef calculate_reward(self, user):pass

然后,为每个等级实现具体的策略类:

class Level1Reward(RewardStrategy):def calculate_reward(self, user):return 10  # 假设等级1的用户获得10积分class Level2Reward(RewardStrategy):def calculate_reward(self, user):return 20  # 假设等级2的用户获得20积分# ... 为其他等级实现策略类 ...class Level100Reward(RewardStrategy):def calculate_reward(self, user):return 1000  # 假设等级100的用户获得1000积分

接下来,定义一个奖励计算器,它使用策略模式:

class RewardCalculator:def __init__(self):self.strategies = {1: Level1Reward(),2: Level2Reward(),# ... 为其他等级添加策略对象 ...100: Level100Reward(),}def get_reward(self, user):level = user.levelstrategy = self.strategies.get(level)if strategy:return strategy.calculate_reward(user)else:return 0  # 或者抛出异常,表示无效的等级

最后,使用这个奖励计算器:

class User:def __init__(self, level):self.level = levelcalculator = RewardCalculator()
user = User(1)  # 假设用户等级为1
reward = calculator.get_reward(user)
print(f"User with level {user.level} received {reward} points.")

这种设计方法的优点在于:

性能:由于我们为每个等级预先定义了策略对象,因此查找和计算奖励的时间复杂度是O(1)。
可扩展性:如果需要添加新的等级或修改某个等级的规则,我们只需要添加或修改相应的策略类,而不需要修改其他代码。
易读性和维护性:每个等级的规则都被封装在单独的类中,使得代码更加清晰和易于维护。

C++示例

在C++中,抽象类和抽象方法的实现略有不同。C++使用= 0来标记一个纯虚函数(即抽象方法),并使用class关键字后加上abstract来声明一个抽象类(在C++11及以后的版本中,这并非强制性的,因为只要类中含有纯虚函数,它就是抽象的)。以下是将您提供的Python抽象类RewardStrategy转换为C++代码的示例:

#include <iostream>
#include <memory> // for std::unique_ptr// 抽象类 RewardStrategy,包含纯虚函数 calculate_reward
class RewardStrategy {
public:virtual ~RewardStrategy() = default; // 虚析构函数,确保正确释放派生类对象// 纯虚函数,需要在派生类中实现virtual int calculate_reward(const User& user) const = 0;
};// 假设有一个User类,其中包含level属性
class User {
public:User(int level) : level_(level) {}int getLevel() const { return level_; }private:int level_;
};// 具体的策略类,继承自 RewardStrategy 并实现纯虚函数
class Level1Reward : public RewardStrategy {
public:int calculate_reward(const User& user) const override {return 10; // 假设等级1的用户获得10积分}
};class Level2Reward : public RewardStrategy {
public:int calculate_reward(const User& user) const override {return 20; // 假设等级2的用户获得20积分}
};// ... 可以为其他等级实现类似的策略类 ...// 奖励计算器类,使用策略模式
class RewardCalculator {
public:// 假设有一个map来存储等级到策略的映射std::map<int, std::unique_ptr<RewardStrategy>> strategies;RewardCalculator() {// 初始化策略映射strategies[1] = std::make_unique<Level1Reward>();strategies[2] = std::make_unique<Level2Reward>();// ... 为其他等级添加策略对象 ...}int getReward(const User& user) {auto it = strategies.find(user.getLevel());if (it != strategies.end()) {return it->second->calculate_reward(user);} else {return 0; // 或者可以抛出异常,表示无效的等级}}
};int main() {User user(1); // 假设用户等级为1RewardCalculator calculator;int reward = calculator.getReward(user);std::cout << "User with level " << user.getLevel() << " received " << reward << " points." << std::endl;return 0;
}

在C++代码中,我们使用了std::map来存储每个等级对应的策略对象的唯一指针(std::unique_ptr)。std::unique_ptr是C++11引入的智能指针,用于自动管理对象的生命周期。我们还在RewardStrategy类中添加了虚析构函数,以确保在删除派生类对象时,它们的析构函数也会被正确调用。

此外,C++中的纯虚函数使用= 0来标记,并在派生类中使用override关键字来明确表示我们是要重写基类的虚函数。const关键字用于表明calculate_reward函数不会修改其参数或类的任何成员变量,且返回值也不依赖于任何对象的可变状态。

请注意,这个示例假设User类已经存在,并且有一个getLevel方法来获取用户的等级。您可能需要根据实际情况调整User类的定义。

总结

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

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

相关文章

spring-cloud-alibaba微服务Sentinel

Sentinel 官方网站 sentinel-dashboard-1.8.7.jar包下载地址 在window通过命令行启动&#xff08;java -Dserver.port8080 -Dproject.namesentinel-dashboard -jar sentinel-dashboard-1.8.7.jar&#xff09;&#xff0c;可以通过 -Dserver.port修改控制台的端口 使用的版本最好…

CentOS7.9.2009安装配置logstash7.11.1

本文章使用CentOS7.9.2009服务器以root用户安装配置logstash7.11.1软件 1.服务器信息 [root@elasticsearch ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [root@elasticsearch ~]# 2.logstash安装配置 --> 上传logstash7.11.1版本至CentOS7.9.200…

【设计模式】4、prototype 原型模式

四、prototype 原型模式 https://refactoringguru.cn/design-patterns/prototype 如果希望 复制对象, 可使用 “prototype 模式” 如果 “待复制的对象” 是 interface 而不是 class, 或者如果 class 有 private 变量时. 无法知道 "待复制的对象"的细节, 则需要其…

Python 全栈 Web 应用模板:成熟架构,急速开发 | 开源日报 No.223

tiangolo/full-stack-fastapi-template Stars: 15.6k License: MIT full-stack-fastapi-template 是一个现代化的全栈 Web 应用模板。 使用 FastAPI 构建 Python 后端 API。使用 SQLModel 进行 Python SQL 数据库交互&#xff08;ORM&#xff09;。Pydantic 用于数据验证和设…

Linux目录和文件管理

Linux 目录结构 是树形结构&#xff0c;默认是以 根目录 / 为所有文件、目录的起点 目录介绍/root 超级用户(系统管理员)的主目录(特权阶级)/home存放所有用户文件的根目录&#xff0c;是用户主目录的基点&#xff0c;比如用户user的主目录就是/home/user&#xff0c;可以…

ARM的TrustZone技术

ARM的TrustZone技术是一种系统范围的安全解决方案&#xff0c;旨在为高性能计算平台上的各种应用提供保护&#xff0c;如安全支付、数字版权管理、企业服务和基于Web的服务。其核心原理是通过硬件级别的隔离和保护来增强系统的安全性。 工作原理 TrustZone技术通过在ARM架构中…

NODE MCU (ESP8285-ESP8266)用Arduino lDE 2.3.2烧录系统后串口监控不打印问题

问题: Arduino lDE 2.3.2,集合DOIT ESP-Mx DevKit板子,烧录代码后,串口监视器 打印不出来调试数据 分析: Arduino lDE 2.3.2工具提示,不支持调试 板载flash按钮无需按下,即可烧录系统,由于烧录和调试共用串口,所以怀疑是Arduino lDE 2.3.2在烧录时设置了串口的配置…

YOLTV8 — 大尺度图像目标检测框架(欢迎star)

YOLTV8 — 大尺度图像目标检测框架【ABCnutter/YOLTV8: &#x1f680;】 针对大尺度图像&#xff08;如遥感影像、大尺度工业检测图像等&#xff09;&#xff0c;由于设备的限制&#xff0c;无法利用图像直接进行模型训练。将图像裁剪至小尺度进行训练&#xff0c;再将训练结果…

C语言--内存函数

1.memcmp使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); 函数memcpy从 source 的位置开始向后 复制num个 字节的数据到 destination 指向的内存位置。 这个函数在遇到 \0 的时候并 不会停下来 。 如果source和destination有任何…

Echarts简单的多表联动效果和添加水印和按钮切换数据效果

多表联动 多表联动效果指的是在多个表格之间建立一种交互关系&#xff0c;以便它们之间的操作或选择能够相互影响。通常情况下&#xff0c;多表联动效果可以通过以下方式之一实现&#xff1a; 数据关联&#xff1a; 当在一个表格中选择或操作某些数据时&#xff0c;另一个表格…

练习4-11 统计素数并求和

本题要求统计给定整数M和N区间内素数的个数并对它们求和。 输入格式: 输入在一行中给出两个正整数M和N&#xff08;1≤M≤N≤500&#xff09;。 输出格式: 在一行中顺序输出M和N区间内素数的个数以及它们的和&#xff0c;数字间以空格分隔。 输入样例: 10 31输出样例: 7…

java数据结构与算法刷题-----LeetCode476. 数字的补数

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 位运算&#xff1a;取出非前导0位标1&#xff0c;进行异或2. …

Hadoop 3.1.3

第1章 Hadoop概述 1.1 Hadoop是什么 1.2 Hadoop发展历史&#xff08;了解&#xff09; 1.3 Hadoop三大发行版本&#xff08;了解&#xff09; Hadoop三大发行版本&#xff1a;Apache、Cloudera、Hortonworks。 Apache版本最原始&#xff08;最基础&#xff09;的版本&#x…

HTML基本语法

前言&#xff1a; html中不区分大小写&#xff0c;但建议用小写&#xff0c;因为使用组件时一般使用大写&#xff0c;便于区分两者 注释&#xff1a; <!-- 注释的内容 --> ~注释的内容只会显示在源码当中&#xff0c;不会显示在网页中 ~用于解释说明代码&#xff0c;或隐…

Unity 2D让相机跟随角色移动

相机跟随移动 最简单的方式通过插件Cinemachine 在窗口/包管理器选择全部找到Cinemachine&#xff0c;导入。然后在游戏对象/Cinemachine创建2D Camera。此时层级中创建一个2D相机。选中人物拖入检查器Follow。此时相机跟随人物移动。 修改相机视口距离 在检查器中Lens下调正…

Java开发从入门到精通(二十):Java的面向对象编程OOP:Stream流

Java大数据开发和安全开发 &#xff08;一&#xff09;Java的新特性&#xff1a;Stream流1.1 什么是Stream?1.2 Stream流的使用步骤1.3 获取Stream流1.4 Stream流常见的中间方法1.5 Stream流常见的终结方法 &#xff08;一&#xff09;Java的新特性&#xff1a;Stream流 1.1 …

1. 信息存储

系列文章目录 信息的表示和处理 : Information Storage&#xff08;信息存储&#xff09;Integer Representation&#xff08;整数表示&#xff09;Integer Arithmetic&#xff08;整数运算&#xff09;Floating Point&#xff08;浮点数&#xff09; 文章目录 系列文章目录前…

STM32常见调试工具介绍

STM32的常见调试工具主要包括ST-LINK、USB转TTL、USB转485以及USB转CAN。这些工具在嵌入式系统开发、调试以及通信中发挥着重要的作用。 1.ST-LINK&#xff1a; ST-LINK是STMicroelectronics公司专为其STM32系列微控制器开发的调试和编程工具。既能仿真也能将编译好的程序下载…

自动化收集Unity版本更新日志

自动化收集Unity版本更新日志 &#x1f365;功能介绍&#x1f96a;食用手册填写配置开始搜集 &#x1f368;数据展示 &#x1f365;功能介绍 &#x1f4a1;获取指定年份中所有的Unity版本更新日志。 &#x1f4a1;根据指定字符串过滤。 &#x1f4a1;.收集后自动保存成markdow…

无线通信:双工(Duplex)方式

什么是双工方式 所谓双工&#xff0c;就是指通信双方之间可以双向通信&#xff0c;每一方都可以发送信息&#xff0c;也可以接收信息。双工方式是指通信双方如何进行发送和接收信息的形式。 有哪些双工方式 传统的双工方式主要有两种&#xff0c;即TDD和FDD。 TDD&#xff…