一,前言
本项目中我们实现了一个模拟在线答题判分的程序,分为三次迭代,逐步扩展功能和复杂度。通过三次题目集的练习,我们从基本的答题判分系统开始,逐渐加入了多试卷、多学生、多题目管理等元素,最终形成一个多功能、多用户的答题管理系统。每个题目集中涉及的知识点包括输入处理、字符串解析、数据结构设计等,难度也从单一判题逐渐增加到复杂的试卷和学生信息的管理。题目数量递减,由5道题目递减到3道题目,但难度逐步递增。
二,设计与分析
1.题目集1第1题 设计一个风扇Fan类
本题要求我们设计一个Fan类来表示风扇的各项属性和行为。我们将风扇的速度、是否开启、半径、颜色作为数据成员,并提供相应的构造方法、访问器、修改器以及字符串输出方法。下面是主要的设计和分析:
1.类的常量:定义SLOW、MEDIUM和FAST三个常量,分别用1、2、3表示不同的速度。这使得速度有更清晰的表达方式,便于调用。
2.数据成员:
speed:整型,表示风扇的速度,默认为SLOW。
on:布尔型,表示风扇的开关状态,默认为false。
radius:双精度浮点型,表示风扇的半径,默认为5。
color:字符串类型,表示风扇的颜色,默认为white。
3.构造方法:
无参构造方法:初始化风扇为默认状态。
有参构造方法:接收速度、开关状态、半径和颜色参数,自定义风扇属性。
4.访问器和修改器:提供每个数据成员的get和set方法,使数据成员符合封装性原则。
5.toString() 方法:根据风扇是否开启返回描述信息。如果风扇开启,返回速度、颜色、半径及“fan is on”;如果风扇关闭,返回速度、颜色、半径及“fan is off”。
6.测试用例:要求创建两个风扇对象,一个是无参构造的默认风扇Fan1,另一个是根据用户输入的属性创建的自定义风扇Fan2,并通过调用toString方法输出风扇信息。
类图
7.注意事项
需要注意toString()方法中的条件判断,确保风扇在不同状态下输出的描述信息符合题目要求。
构造方法中的参数应当被适当地初始化到类的相应字段中,并考虑到非法输入的检查,例如速度的值限制在1到3之间。
注意设计输出格式,使其与题目样例严格一致,避免因格式错误影响测试通过率。
8.主要执行代码
// 创建风扇对象并从用户输入中获取风扇的属性
Fan fan1 = new Fan();
Scanner scanner = new Scanner(System.in);
int speed = scanner.nextInt();
boolean on = scanner.nextBoolean();
double radius = scanner.nextDouble();
scanner.nextLine();
String color= scanner.next();
// 使用用户输入的属性创建第二个风扇对象
Fan fan2 = new Fan(speed,on,radius,color);
// 输出两个风扇的信息
System.out.println("-------\nDefault\n-------");
System.out.println(fan1.tostring());
System.out.println("-------\nMy Fan\n-------");
System.out.println(fan2.tostring());
2.题目集1第5题 答题判题程序-1
题目要求设计一个简易的答题系统,接收题目信息和用户答案,进行判题并输出结果。代码主要分为几个关键部分,包括读取题目信息、保存答题信息、判题、以及输出结果。
- 需求分析
输入:
题目数量:一个整数。
题目内容:每个题目包含题号、题目内容和标准答案,顺序不定。
答题信息:每题的答案,顺序与题目题号对应,后接"end"表示结束。
输出:
题目与用户答案:按照题目内容和用户答案顺序输出。
判题结果:输出“true”或“false”表示用户答案的正确性,顺序与题目题号一致。
- 代码结构与功能
代码通过几个类来管理题目和答案信息。
Main 类:主程序逻辑,负责读取输入并进行初始化。
Paper 类:用来存储所有题目。
Question 类:表示一个题目,包含题号、题目内容、标准答案,以及判题方法。
AnswerSheet 类:存储用户的答题信息并负责判题和输出。
- 代码详解
Main 类
Main类的main方法首先读取题目数量,并使用循环读取每道题目内容。
使用正则表达式拆分输入字符串,解析题号、题目内容、和标准答案,并添加到Paper实例中。
读取用户的答题信息,直到读取到"end"。将用户的答案与题号对应,存储在AnswerSheet实例中。
Paper 类
Paper类维护一个HashMap,存储每道题的题号和题目信息。
提供addQuestion方法用于保存题目,getAllQuestions方法用于获取所有题目。
Question 类
Question类用于存储题目的内容、标准答案及相关方法。
isStandardAnswer方法用于判断用户的答案是否正确.
AnswerSheet 类
AnswerSheet类包含用户的答题信息和判题结果。
addAnswer方法接收用户答案,存储到HashMap中。
judges方法遍历所有题目,并通过judge方法逐题判定正误,将结果存入jud列表。
output方法负责格式化输出题目内容、用户答案和判题结果。
-
关键逻辑
题目解析:使用正则表达式解析题目内容,split("#N:|#Q:|#A:")从原始字符串中提取题号、题目内容和标准答案。
判题:通过Question类中的isStandardAnswer方法判定每道题目的正误,结果存入List。
输出:output方法按要求格式化输出,每道题目和答题信息逐行显示,判题信息以“true”和“false”表示,按用户输入的顺序。
// 遍历试卷中的所有问题并对用户的答案进行判断
for (Question q : paper.getAllQuestions()) {
String givenAnswer = answer.get(q.getNum());//用户答案
jud.add(judge(givenAnswer,q));
} -
类图
-
踩坑心得
在解析题目内容和答题信息时,使用正则表达式拆分字符串。若输入格式不规范(如多余空格、标记位置不对等),可能导致解析失败或抛出异常。
解决方案:
在使用正则表达式解析输入内容时,要确保去除多余空格,并捕获异常。trim()可以清除多余空格,同时增加异常处理,确保即便输入格式不严格,也能处理。
// 1. 读取题目数量
int questionCount = Integer.parseInt(scanner.nextLine().trim());
Paper paper = new Paper();
for (int i = 0; i < questionCount; i++) {
String line = scanner.nextLine().trim();
// 使用正则表达式解析题目信息
String[] parts = line.split("#N:|#Q:|#A:");
int num = Integer.parseInt(parts[1].trim());
String question = parts[2].trim();
String standardAnswer = parts[3].trim();
paper.addQuestion(num, question, standardAnswer);
} -
改进建议
对于答案判断部分的改进,去除冗余方法:原来的 judge 方法只是调用 isStandardAnswer 方法,因此直接在 judges 方法中调用 isStandardAnswer 可以减少方法调用的开销。
添加错误处理:在判断答案的同时增加了对 givenAnswer 是否为空的判断,以避免潜在的空指针异常。
public void judges() {
// 遍历试卷中的所有问题并对用户的答案进行判断
for (Question q : paper.getAllQuestions()) {
String givenAnswer = answer.get(q.getNum());//用户答案
jud.add(judge(givenAnswer,q));
}
}
public boolean judge(String answer,Question q){
return q.isStandardAnswer(answer);
}
改进后
public void judges() {
// 遍历试卷中的所有问题并对用户的答案进行判断
for (Question q : paper.getAllQuestions()) {
String givenAnswer = answer.get(q.getNum()); // 用户答案
// 使用安全的判断机制,避免空指针异常
jud.add(givenAnswer != null && q.isStandardAnswer(givenAnswer));
}
}
3.题目集2第4题
本题基于前题(答题判题程序-1)的基础上进行扩展。核心任务是设计一个答题判题程序,增加试卷(TestPaper)和答卷(AnswerSheet)功能,以便通过多种输入信息动态生成考试题目、计算分数并输出判题结果。
1.主要设计:
输入信息的解析:新增了试卷信息(包含试卷号和题目分值)和答卷信息(包含试卷号和答案),并要求能处理题目、试卷、答卷混合顺序输入,支持题号缺失和分值不满100分的试卷。
判题和评分的灵活性:题目支持缺失题号,答卷支持题目答案数量与试卷不一致。分值不满100的试卷会触发警告但不影响正常判分。
面向对象设计的扩展性:为了适应新增的试卷和答卷信息,设计了题目类(Question)、试卷类(TestPaper)、答卷类(AnswerSheet),各类职责单一,方法清晰,便于维护和扩展。
2. 需求分析
输入:
题目信息:每行包含题号、题目内容和标准答案,顺序不定,题号可能缺失。
格式:#N:题目编号 #Q:题目内容 #A:标准答案
样例:#N:1 #Q:1+1= #A:2
试卷信息:每行代表一张试卷,包含试卷号、题目编号和题目分值。
格式:#T:试卷号 题目编号-题目分值
样例:#T:1 1-5 2-8
答卷信息:每行包含一个试卷的答案,包含试卷号和该试卷题目的答案。
格式:#S:试卷号 #A:答案内容
样例:#S:1 #A:5 #A:22
输出:
试卷总分警示:若试卷总分不等于100分,则输出提示信息。
格式:alert: full score of test paper 试卷号 is not 100 points
题目与用户答案:按照题目顺序输出题目内容、用户答案和判题结果。
格式:题目内容~答案~判题结果(true/false)
判分信息:输出每道题目的得分和总分,按照输入顺序排列。
格式:题目得分1 题目得分2 ... ~ 总分
错误的试卷号提示:如果答案信息中的试卷号找不到,输出错误提示。
格式:the test paper number does not exist
- 代码结构与功能
代码采用面向对象的设计,共由四个主要类组成:Main 类、Question 类、TestPaper 类、AnswerSheet 类。
Main 类
主程序逻辑:负责读取题目信息、试卷信息、答卷信息的输入,对数据进行解析和初始化。
输入数据解析:根据前缀#N:, #T:, #S:判断信息类型并调用相应解析方法。
输出数据格式化:判定试卷总分,输出判题结果和答题总分。
Question 类
功能:表示一道题目,包含题号、题目内容和标准答案。
方法:
isCorrectAnswer(String answer):判断用户答案是否正确。
TestPaper 类
功能:存储一张试卷的信息,包括试卷号和题目编号、题目分值。
方法:
addQuestion(int num, int score):添加题目及其分值。
isFullScoreValid():判断试卷总分是否为100分。
AnswerSheet 类
功能:存储答卷信息并负责判分与输出结果。
方法:
judgeAnswers():判定答案的正确性并输出结果。
calculateScore():计算每个题目的得分并输出总分
-
边界条件
单个题目与试卷:确保系统能够处理单一题目和单一试卷的情况。
题号缺失:支持题号非连续的输入,并保证按顺序输出。
答案缺失:答卷中的答案数量少于试卷中的题目数量时,输出“answer is null”并得0分。
多余答案:答卷中的答案多于试卷中的题目数量时,忽略多余的答案。
无效试卷号:答卷中的试卷号不存在时,输出错误提示“the test paper number does not exist”。 -
类图
-
踩坑心得
标签:输出,题目,试卷,信息,贺凯凯,Blog,22207208,判题,输入 From: https://www.cnblogs.com/Dream-Xi/p/18502894
1. 对于输入的题目#N:1 #Q:1+1= #A:2,以空格分隔解析,出现非零返回错误
if(input.startsWith("#N")){
String[] parts = input.split(" ");//这里
int questionNum = Integer.parseInt(parts[0].split("