首页 > 编程语言 >HNU个人项目互评——中小学数学卷子自动生成程序

HNU个人项目互评——中小学数学卷子自动生成程序

时间:2023-09-20 09:00:14浏览次数:37  
标签:std 题目 函数 代码 互评 HNU 卷子 class 输入

HNU个人项目互评——中小学数学卷子自动生成程序

  • 代码作者:刘蕴哲
  • 评价人:李锦华

一、个人项目需求

1. 用户

小学、初中和高中数学老师。

2. 功能

(1)命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初中和高中三个选项中的一个。否则提示“请输入正确的用户名、密码”,重新输入用户名、密码;

(2)登录后,系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。每道题目的操作数在1-5个之间,操作数取值范围为1-100;

(3)题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录),程序根据输入的题目数量生成符合小学、初中和高中难度的题目的卷子(具体要求见附表)。同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重复(以指定文件夹下存在的文件为准,见5);

(4)在登录状态下,如果用户需要切换类型选项,命令行输入“切换为XX”,XX为小学、初中和高中三个选项中的一个,输入项不符合要求时,程序控制台提示“请输入小学、初中和高中三个选项中的一个”;输入正确后,显示“”系统提示“准备生成XX数学题目,请输入生成题目数量”,用户输入所需出的卷子的题目数量,系统新设置的类型进行出题;

(5)生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。每道题目有题号,每题之间空一行;

3. 附表

附表-1:账户、密码

账户类型 账户 密码 备注
小学 张三1 123
张三2 123
张三3 123
初中 李四1 123
李四2 123
李四3 123
高中 王五1 123
王五2 123
王五3 123

附表-2:小学、初中、高中题目难度要求

小学 初中 高中
难度要求 +,-,*./ 平方,开根号 sin,cos,tan
备注 只能有+,-,*./和() 题目中至少有一个平方或开根号的运算符 题目中至少有一个sin,cos或tan的运算符

二、功能测试

1. 登录

用户名密码错误时显示:

登录成功后显示:

2. 生成题目

生成10道题:

3.退出当前用户

输入-1后:

三、代码分析

1. classes.h

(1) 优点

① 注释详细:代码中包含了详细的注释,解释了各个部分的功能和逻辑,有助于其他开发者理解和维护代码。(以下截取一段为例)

// MyLog类是在主程序中可见的单例类,声明了获取实例函数,命令行分析函数,
// 输入获取函数和Level-char数组转化函数
// 作为与命令行广泛交互的类而存在,通过智能指针,会在程序结束时自动销毁
class MyLog {
 public:
  ~MyLog() {}
  // 登录验证函数,掌控用户的登录入口
  // 返回可以代表用户登录成功与否的整型数据
  int VerifyUser();
  // 获取实例函数,经典的懒汉式实现
  // 返回共享型智能指针
  static std::shared_ptr<MyLog> GetInstance();
  // 命令行分析函数,用于登陆后用户的命令分析,
  // 根据不同的输入指令产生不同的响应或是调用特定的函数
  // 输入一个int指针,用于主程序判断执行指令后的程序执行方向
  // 第二个参数式User类型的指针,获取用户信息,改变工作状态需要
  void AnalyseCommand(int* flag, User* user);
  // 输入函数,获取命令行输入并自动去除换行回车
  // 纯功能型函数,因为重用而干脆写成函数
  // 被VerifyUser和AnalyseCommand调用
  void MyInput();
  // 转换函数,因为AnalyseCommand过于冗长而将level到char*的转化
  // 移植到此处,只有AnalyseCommand调用来在终端输出字符串
  std::string TransformLevel(Level input);
  // 获取已注册用户的工作状态:小学,初中,高中
  // 登录时被VerifyUser调用
  Level user_level(int index) { return user_level_[index]; }
  // 获取已存在用户的账户密码,方便比对
  // 登录时被VerifyUser调用
  char* users(int index) { return users_[index]; }

② 采用命名空间:代码中使用了命名空间,有助于避免命名冲突,提高了代码的可维护性。

namespace myproject_classes {}

③ 使用了智能指针:代码中使用了 std::shared_ptr,这有助于避免内存泄漏和管理对象的生命周期。

  // 智能指针,不多赘述
  // 定义成私有是为了单例模式需要客户端无法多次定义
  static std::shared_ptr<MyLog> my_instance_;

④ 使用工厂模式:代码中使用了工厂模式来创建不同类型的用户对象,这有助于扩展代码以支持不同类型的用户。

class UserFactory {}
class TeacherFactory {}

⑤ 模块化:代码将不同的功能模块化,每个功能有自己的函数或类,提高了代码的可读性和可维护性。

class User {}
class MyLog {}
class Teacher {}
class UserFactory {}
class TeacherFactory {}
class MyMath {}
class FileSystem {}

(2) 缺点

① 内存管理问题:User 类中的 account_ 成员使用裸指针 char*,但没有进行内存管理。最好使用 std::string 来管理字符串,以避免内存泄漏和访问越界。

  // 账户密码获取函数
  char* account() { return account_; }

② 缺少异常处理:代码中没有考虑异常处理机制,如果发生错误,程序可能会崩溃而不是 graceful 地处理错误

③ 静态成员函数过多:MyMath 和 FileSystem 类中的所有函数都是静态的,这可能导致代码的可测试性较差。考虑将一些功能分解成更小的非静态成员函数,以提高可测试性和可维护性。

2. classes.cc

(1) 优点

① 文件操作和字符串处理: 代码实现了文件读取和写入的功能,以及字符串处理,这些功能在实际应用中是非常常见和重要的。

// GetBank获取bank文件中的题库
// 由c自带的文件读写实现(某些情况比文件输入流更方便)
// 主要是因为老师说只准用文件输出流,不然文件输入流更方便
// 先声明一个256的文件路径数组
// 然后让account参数合成来的文件路径格式化后赋值给路径数组
// 通过路径数组打开文件,然后一个个字符的读,加到content字符串末尾
// 最后关闭文件,返回content字串,便获得了题库
std::string FileSystem::GetBank(char* account) {
  // 文件路径字符数组
  char dir_path[256] = { NULL };
  // 读取的单个字符
  char c;
  // C++的内容字符串
  std::string content = "";
  snprintf(dir_path, sizeof(dir_path), "./%s/bank.txt", account);
  FILE* bank_file = NULL;
  if (!fopen_s(&bank_file, dir_path, "r")) {
    while ((c = fgetc(bank_file)) != EOF) {
      content += c;
    }
    fclose(bank_file);
  }
  return content;
}
// 创建试卷文件并将题目字符串放入文件的函数
// 首先通过windows的库函数获取本地时间
// 然后通过snprintf将时间格式化输出到字符串tmp中
// 通过格式化的时间串和文件夹名参数生成对应路径
// 通过C++文件输出流配合std::ios::trunc参数创建文件
// 让传入的content字符串,即题目流转到文件中
// 关闭文件即完成了创建
void FileSystem::SetFile(std::string content, std::string name) {
  // windows的系统时变量
  SYSTEMTIME sys;
  // 获取本地时间
  GetLocalTime(&sys);
  // 文件名存储字符串
  char tmp[64] = { NULL };
  snprintf(tmp, sizeof(tmp), "%4d-%02d-%02d-%02d-%02d-%02d",
    sys.wYear, sys.wMonth, sys.wDay,
    sys.wHour, sys.wMinute, sys.wSecond);
  std::string file_name = "./" + name + "/" + std::string(tmp) + ".txt";
  std::ofstream file(file_name, std::ios::out | std::ios::trunc);
  file << content;
  file.close();
}

② 单例模式实现: 代码中使用了单例模式,确保了只有一个实例对象,并提供了一个全局访问点,以保持数据的一致性。(以下截取部分代码)

// MyLog类是在主程序中可见的单例类,声明了获取实例函数,命令行分析函数,
// 输入获取函数和Level-char数组转化函数
// 作为与命令行广泛交互的类而存在,通过智能指针,会在程序结束时自动销毁
class MyLog {
 private:
  // 智能指针,不多赘述
  // 定义成私有是为了单例模式需要客户端无法多次定义
  static std::shared_ptr<MyLog> my_instance_;
}

(2) 缺点

① 代码冗余: 一些函数如Add、Subtract、Multiply、Divide等的代码结构相似,存在大量重复的代码,不利于维护和扩展。可以考虑将这些共通的部分提取出来,减少重复。

② 错误处理不足: 代码中的错误处理相对简单,例如,文件打开失败后没有进行错误处理,可以添加更多的错误检查和异常处理机制,以提高代码的健壮性。

③ 平台依赖性: 代码中使用了一些Windows平台特定的函数,如GetLocalTime,这会导致代码在不同平台上不可移植。如果需要跨平台支持,需要使用跨平台的替代函数或抽象接口。

  // 获取本地时间
  GetLocalTime(&sys);

3. paper_generator.cc

(1) 优点(多数优点此前已经有过介绍,不多赘述)

① 注释详细:代码中包含了详细的注释,解释了各个部分的功能和逻辑,有助于其他开发者理解和维护代码。

② 采用命名空间:代码中使用了命名空间,有助于避免命名冲突,提高了代码的可维护性。

// 以下是需要从classe.h的命名空间中导入的类
using myproject_classes::MyLog;
using myproject_classes::User;
using myproject_classes::UserFactory;
using myproject_classes::TeacherFactory;

③ 使用了智能指针:代码中使用了 std::shared_ptr,这有助于避免内存泄漏和管理对象的生命周期。

④ 使用工厂模式:代码中使用了工厂模式来创建不同类型的用户对象,这有助于扩展代码以支持不同类型的用户。

⑤ 模块化:代码将不同的功能模块化,每个功能有自己的函数或类,提高了代码的可读性和可维护性。

(2) 缺点:

① 内存泄漏潜在问题:代码中使用了 new 来创建 UserFactory 对象,但没有对其进行释放(delete),这可能导致内存泄漏。应该使用智能指针或在适当的时候手动释放内存。

  // 先创建一个工厂,由老师工厂来具体实现
  UserFactory* factory = new TeacherFactory();

② 不支持异常处理:代码没有考虑到异常处理机制,如果在运行时发生异常,程序可能会崩溃而不是 graceful 地处理错误。

③ 单一职责原则:main 函数的功能相对较大,包括用户登录、命令解析和业务逻辑等,这违反了单一职责原则,可以考虑将其拆分成更小的函数或类以提高代码的可维护性。

四、总结

​ 总的来说,刘蕴哲同学的代码是十分优秀的范例,实现了基本功能,拥有优秀的模块化设计,使用了诸如工厂模式、单例模式等设计模式,同时,还使用了智能指针来管理对象的生命周期,整体设计合理、别出心裁,希望日后能在内存泄漏、异常处理等细节方面有所改进。

标签:std,题目,函数,代码,互评,HNU,卷子,class,输入
From: https://www.cnblogs.com/Narniaaagh/p/17716406.html

相关文章

  • 中小学数学卷子自动生成程序-个人项目互评
    前言:首先,很有幸能有这样一次和队友互相学习的机会。正好我们两个人都是选择的C++,通过对比分析对方的代码,学习到了很多,也深刻认识到了自己的不足,还有很长的路要走。程序结构:队友的代码用了一个cpp文件便包含了所有代码,这稍微有点不好,如果能够将各个功能函数各自放在头文件,就能让......
  • 结对项目互评
    1.队友代码测试登陆注册(要求外添加的功能)退出出题(以下为三种难度的题目)切换难度切换账号2.代码分析接下来将主要分析核心代码首先是展示模块,这部分代码刘同学主要用了两个类来实现首先是正常输入正确的情况点击查看代码packagelogin;impor......
  • 个人项目:中小学数学卷子自动生成程序互评
    前言:我和队友使用的都是c++来实现这个程序,通过沟通交流,我们明白了彼此代码的优缺点,对这个程序有了更深的理解。 结构:队友的代码主要包括一个cpp文件和三个h头文件,将功能函数分散开来,我觉得这是一个很好的点。优点:1.功能分解成了多个函数,在运行时方便查找错误出现的位置; ......
  • HNU结对编程之队友代码互评
    一、前言在本次互评中,我有幸审阅了zjx同学的项目。zjx同学的代码风格严谨,对于代码规范的遵循和对于项目需求的理解都让人印象深刻。以下是我对他的项目的评价和建议。 二、测试1.黑盒测试我首先进行了黑盒测试,也就是从用户的角度,不考虑程序内部结构和属性,只关注程序的输入......
  • 个人项目互评代码分析
    个人项目互评代码分析软件2105-刘一凡在看完金颖希同学的代码后,我有了一些看法与建议,在这篇博客中将对她的代码进行分析,并提出一些建议性的优化方案。个人拙见,希望能为项目的进一步改进提供一些思路。整体结构:代码结构相对清晰,分为数学题生成器和用户两部分,其中每个数学题生成......
  • 个人项目互评
    一.整体分析:苏晨阳同学的代码包括了大量的类,大致分析如下:1.User类:这是一个抽象类,包含了用户的基本信息(name、password、authority)和一个设置用户权限的方法。其他用户类(如Teacher)可以继承这个类来共享属性和方法。2.Teacher类:这个类继承了User类,表示教师用户。它包含了各种方......
  • HNU个人项目互评——中小学数学卷子自动生成程序
    结对编程互评代码作者:软件2104潘胜蓝互评作者:软件2104苏晨阳一、摘要该作业是由潘胜蓝同学使用Java语言完成的“中小学数学卷子自动生成程序”。在代码设计方面,对小学教师、初中教师、高中教师三种角色属性进行了抽象提取,利用java抽象类和继承的优点进行编写;通过自行编......
  • HNU个人项目互评:中小学数学卷子自动生成程序
    一、功能测试1.登录功能命令行输入用户名与密码,当用户名与密码都正确时,显示当前为XX出题 正常输入时功能正常,但是当只输入用户名时发生了异常,应该是没有考虑只输入一个(没有测试bug呀!)Stringstr[]=in.nextLine().split("\\s+");nuser.setName(str[0]);......
  • 个人项目互评
    软件2103桑健康队友李明胜功能测试登录模块需求:系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。每道题目的操作数在1-5个之间,操作数取......
  • 个人项目互评
    本博客为湖南大学2021级软件工程导论课程的结对小组个人项目互评。根据本课程“做中学”的要求,我们第一周完成了个人项目代码,现在结对完成代码互评。编程语言:C++结对成员:顾问、郑雨凡文章作者(评价人):顾问代码作者:郑雨凡一、个人项目要求:用户:小学、初中和高中数学老师......