目录
一、前言
1.1 知识点
(1)题目集1
题目集1中涉及到类的定义与封装、数据域的访问与控制、数组与集合的使用、以及字符串处理等知识点,在这次作业中,我对于面向对象编程中封装的概念有了具体的认识,掌握了数组和ArrayList集合的使用方法,并且我还学会了对字符串的一些简单处理。
(2)题目集2
题目集2中涉及到方法重写、排序算法、关联类设计和模块化设计等知识点,在这次作业中,我积累了类的设计与定义的经验,学会了用编程实现Compare接口,同时理解了方法重载与方法重写的区别。
(3)题目集3
题目集3中涉及到LocalDate日期类的使用、异常处理、正则表达式提取字符串信息、HashMap集合的使用,在这次作业中,我了解并且使用了正则表达式,能够更灵活地处理字符串从中提取出有用的信息,同时学会了在编程中进行异常处理,对于复杂数据的输入和格式进行验证,编写出一个健壮的程序。
1.2 题量
从第一个题目集到第三个题目集,题目的数量在减小,题目数量最多的是题目集1,一共有五道题,题量适中。
1.3 难度
从第一个题目集到第三个题目集难度呈呈阶梯式上升,第一个题目集我认为是之前练习题向面向对象编程的过程,让我们初步掌握类的设计与定义,掌握面向对象编程中的一些基础知识和语法;第二个题目集相对于第一个题目集难度提高了,需要掌握Compare接口的实现以及对复杂信息的输入输出处理;第三个题目集难度大大提升,需要掌握LocalDate类的使用,对错误输入进行异常处理。
就每个题目集的最后一道大题而言,难度也是逐步提高的,需要设计的类的数量在逐步增加,输入输出的信息更加复杂,要求也更多,到了第三个题目集还需要对输入信息进行异常处理,要求程序具有更强的健壮性。
二、答题判题程序1
2.1 设计与分析
(1)题目简述以及分析
本题要求实现一个模拟答题的程序,用户输入题目数量、题目内容(包括题号、题干、标准答案)和答题信息,程序根据输入的标准答案判断答题结果。输出格式包括每道题的题目内容及用户答案,并输出判题结果。
经过对题目需求的仔细分析并且结合老师给出的类设计的建议,我设计了Main类、Question类、Paper类和AnswerPaper类共四个类,四个类作用如下:
Main类:是程序的入口类,包含了主方法main,负责读取用户输入的数据,创建Paper和AnswerPaper对象,并调用相关方法处理题目和答案,最后输出答题的结果。
Question类:用于封装单个题目的信息,包含了题目编号、题目内容和标准答案的私有数据域,提供相应信息的访问器和修改器的方法,并且提供了判定给定答案是否与标答一致,即是否正确的方法。
Paper类:用于封装一张试卷整套题目的信息,包含题目列表和题目数量的私有数据域,提供了保存题目、获取题目、排序题目以及判断某道题目的答案是否正确的方法。
AnswerPaper类:用于表示一张答卷中的答题信息,包含试卷关联的Paper对象、用户的答案和判题结果,提供了保存用户的答案、判断答案是否正确、保存判题结果,以及输出最终的答题结果的方法。
(2)类图以及source monitor生成报表内容
类图:
source monitor生成报表内容:
根据生成报表内容可知代码的类设计合理,类与类之间的职责分离明确,每个类的方法数量适中,符合单一职责原则,代码圈复杂度为9,代码容易理解和维护。
(3)主要代码分析
1 for (int i = 0; i < countQuestions; i++){ 2 String[] line = input.nextLine().split("#"); 3 int questionNumber = Integer.parseInt(line[1].substring(2).trim()); 4 String content = line[2].substring(2).trim(); 5 String standardAnswer = line[3].substring(2).trim(); 6 paper.saveQuestions(questionNumber, content, standardAnswer); 7 }
上面的代码是题目信息处理和保存的代码,该段代码使用 split("#") 方法,将每道题的输入数据分成多个部分(如题号、题目内容、标准答案),line[1].substring(2).trim()用于
提取题,substring(2)
忽略前缀N:,trim()
去除多余空格,类似地,提取题目内容和标准答案。将这些信息分别存入 Paper 对象中,调用 saveQuestions() 方法。
1 while (input.hasNextLine()){ 2 String line = input.nextLine(); 3 if(line.equals("end")) 4 break; 5 String[] answergroup = line.split("#"); 6 for (int i = 0; i < answergroup.length; i++){ 7 if(answergroup[i].startsWith("A:")){ 8 answerPaper.saveAnswers(answergroup[i].substring(2)); 9 } 10 } 11 }
上面的代码是答卷信息处理和保存的代码,该段代码使用 while (input.hasNextLine())
读取所有输入行,直到遇到 end,结束读取。如果一行数据包含答案(以 A: 开头),则提取答案的部分并存储到 AnswerPaper 中。
1 public void saveResults(){ 2 for(int i = 0; i < paper.getCountQuestions(); i++){ 3 resultList.add(checkAnswer(i + 1)); 4 } 5 }
上述代码是进行答案的判断的代码,在主方法中通过调用 answerPaper.saveResults() 来判断学生的答案是否正确。系统会逐一对比每个问题的标准答案和学生答案,然后将判断结果保存。
2.2 踩坑心得
(1)提交答案显示格式错误
在提取信息时需要注意对信息用trim()
去除多余空格,如果不去除多余的空格的话,在输出时就会将多余空格输出出来,导致出现格式错误。
2.3 改进建议
(1)输入验证
虽然在输入处理时,输入部分的解析通过字符串的分割和裁剪,确保了数据的准确提取,但是我没有在解析输入之前验证输入格式是否正确,这会导致用户输入格式不正确代码会出错,因此需要在代码中添加验证输入格式的程序,以避免异常。
(2)异常处理
我对于输入部分的解析和转换代码只做了正常情况下的处理,没有添加异常处理,这样代码遇到输入错误可能会解析或者转换错误,为了增强代码的健壮性,需要在关键的解析和转换步骤中添加异常处理。
(3)主方法不够简洁
我将对输入信息的解析过程直接写在了主方法中,导致代码不够简洁明了,没有那么容易理解,需要将对输入信息的处理的方法放入的其他类中,让代码有更好的封装性。
3.1 设计与分析
(1)题目简述以及分析
本题在前一个题目的基础上增加了试卷信息的处理、题目编号的灵活性、答案与试卷的对应关系、试卷总分警示、判分信息输出、错误试卷号提示,需要设计更复杂的类结构,从而提升了程序的复杂性和功能性。
经过对题目需求的仔细分析,我设计了Main类、Question类、QuestionBank类、Paper类、PaperBank类、AnswerPaper类、AnswerPaperBank类、InputHandler类和OnputHandler类共九个类,九个类中Question类和前一题一样,Main类、Paper类和AnswerPaper类是在前一题的基础上增加了一些属性和方法,除Question类外其他类的作用如下:
Main类:是程序的入口类,包含了主方法main,负责创建各个类的实例,处理输入并输出结果。
QuestionBank类:用于存储所有题目的集合,提供添加题目和通过题号获取特定题目的方法。
Paper类:用于封装一张试卷整套题目的信息,包含试卷编号、题目列表每题的分值列表和总分的私有数据域,提供了添加题目和计算试卷的总分的方法。
PaperBank类:用于存储所有试卷的集合,提供添加试卷和通过试卷编号获取特定试卷的方法。
AnswerPaper类:用于表示一张答卷中的答题信息,包含试卷关联的Paper对象、答案列表、判题结果列表、得分列表和答卷总分的私有数据域,提供了添加答案、保存判题结果和得分,计算答卷的总得分的方法。
(2)类图以及source monitor生成报表内容
source monitor生成报表内容:
根据生成报表内容可知代码结构清晰,类和方法的分工明确,每个类都有特定的职责,符合面向对象设计原则。InputHandler.handleInput()
的圈复杂度为 12,表明该方法较为复杂,可能需要重构以提高可读性和维护性,其他方法的复杂度普遍较低(1-5),这表明大多数方法都比较简单,整体来说代码圈复杂度适中。
(3)主要代码分析
1 public void handleInput(QuestionBank questionBank, PaperBank paperBank, AnswerPaperBank answerPaperBank) { 2 String line; 3 while (!(line = readLine()).equals("end")) { 4 if (line.startsWith("#N:")) { 5 // 使用正则表达式解析题目信息 6 Pattern pattern = Pattern.compile("#N:(\\d+)\\s+(.*?)\\s+#A:(.*)"); 7 Matcher matcher = pattern.matcher(line); 8 if (matcher.find()) { 9 int questionNumber = Integer.parseInt(matcher.group(1).trim()); 10 String content = matcher.group(2).substring(3).trim(); // 题目内容 11 String standardAnswer = matcher.group(3).trim(); // 标准答案 12 questionBank.addQuestion(new Question(questionNumber, content, standardAnswer)); 13 } else { 14 System.out.println("Warning: Invalid question format: " + line); 15 } 16 } else if (line.startsWith("#T:")) { 17 // 解析试卷信息 18 String[] parts = line.split(" "); 19 int paperNumber = Integer.parseInt(parts[0].substring(3).trim()); 20 Paper paper = new Paper(paperNumber); 21 for (int i = 1; i < parts.length; i++) { 22 String[] questionInfo = parts[i].split("-"); 23 int questionNumber = Integer.parseInt(questionInfo[0].trim()); 24 int score = Integer.parseInt(questionInfo[1].trim()); 25 Question question = questionBank.getQuestion(questionNumber); 26 if (question != null) { 27 paper.addQuestion(question, score); 28 } 29 } 30 paper.computeTotalScore(); 31 paperBank.addPaper(paper); 32 } else if (line.startsWith("#S:")) { 33 // 解析答卷信息 34 String[] parts = line.split(" "); 35 int paperNumber = Integer.parseInt(parts[0].substring(3).trim()); 36 Paper paper = paperBank.getPaper(paperNumber); 37 if (paper == null) { 38 answerPaperBank.addAnswerPaper(null); // 如果找不到试卷,则该答卷在答卷库中为null 39 continue; 40 } 41 AnswerPaper answerPaper = new AnswerPaper(paper); 42 for (int i = 1; i < parts.length; i++) { 43 if (parts[i].startsWith("#A:")) { 44 String answer = parts[i].substring(3).trim(); 45 answerPaper.addAnswers(answer); 46 } 47 } 48 answerPaper.saveResults(); 49 answerPaper.saveScores(); 50 answerPaper.computeAnsTotalScore(); 51 answerPaperBank.addAnswerPaper(answerPaper); 52 } 53 } 54 }
上面的代码负责解析用户输入,并将题目信息、试卷信息和答卷信息存储到相应的类中。它的复杂性主要来自于处理多种输入格式并进行相应的操作。
主要逻辑如下:
1)读取输入:使用 Scanner
读取用户输入,直到输入 "end" 为止。
2)解析题目信息:使用正则表达式匹配题目信息格式 #N:questionNumber #Q:content #A:standardAnswer,
如果匹配成功,则提取题目编号、内容和标准答案,并添加到 QuestionBank
。
3)解析试卷信息:使用正则表达式匹配题目信息格式 #N:questionNumber #Q:content #A:standardAnswer,
如果匹配成功,则提取题目编号、内容和标准答案,并添加到 QuestionBank
。
4)解析答卷信息:识别以 #S:
开头的行,提取答卷对应的试卷编号,并获取相应的 Paper,
处理每个答案,保存结果和得分,计算答卷总分并添加到 AnswerPaperBank
。
3.2 踩坑心得
(1)非零返回
一开始我使用使用 String.split()
方法解析题目信息,导致我忽略了题目的答案中间允许有多个空格,而使用String.split()
不能正确处理这种情况,会让程序出现错误,如下图所示:
解决办法就是使用正则表达式去解析输入信息,避免因为答案中间有空格的情况导致代码运行不成功。
(2)总分警告输出位置不正确
一开始我在解析输入信息时,当解析完试卷信息就对试卷计算总分,若总分不满100分则立即输出总分警告,由于在解析信息时是题目,试卷,答卷信息是一起解析的,就会导致如果有两张试卷,则第二张试卷总分警告不会在答题信息输出之前输出,如下图所示:
解决办法就是在解析题目信息时不做试卷总分的计算,也不做任何输出信息,在主方法中先计算所有试卷的总分,再进行总分警告的输出。
3.3 改进建议
(1)handleInput 方法圈复杂度高
将handleInput 方法中解析题目、试卷和答卷的逻辑拆分成独立的方法,以提高代码可读性和可维护。
(2)异常处理
虽然用了正则表达式能够灵活地解析输入的信息,但如果输入信息格式不对则代码会出现错误,因此需要增加异常处理机制,确保在输入格式不正确时能够进行适当的处理。
四、答题判题程序3
4.1 设计与分析
(1)题目简述以及分析
在本题中,相较于“程序-2”,增加了学生信息和删除题目信息的输入类型,并引入了格式、题目引用错误、学号引用错误等多种提示信息。本题还增强了对题目删除后的处理逻辑,确保被删除题目在试卷中以0分计,并在输出时提示无效。此外,程序-3对答案的优先级判断进行了优化,优先处理答案不存在的情况。这些变化使程序更复杂,功能更全面,特别是在错误处理和信息提示方面。
(2)类图以及source monitor生成报表内容
类图:
source monitor生成报表内容:
(3)主要代码分析
1 public void deleteQuestion(int questionNumber) { 2 allQuestions.remove(questionNumber); 3 deletedQuestions.add(questionNumber); 4 }
- 功能:删除题目并记录已删除的题目编号。
- 逻辑:从
allQuestions
中移除题目,并将题号添加到deletedQuestions
集合中。
1 public void handleInput(QuestionBank questionBank, PaperBank paperBank, StudentBank studentBank, AnswerPaperBank answerPaperBank) { 2 String line; 3 while (!(line = readLine()).equals("end")) { 4 if (line.startsWith("#N:")) { 5 Pattern pattern = Pattern.compile("#N:(\\d+)\\s+#Q:(.*?)\\s+#A:(.*)"); 6 Matcher matcher = pattern.matcher(line); 7 if (matcher.find()) { 8 int questionNumber = Integer.parseInt(matcher.group(1).trim()); 9 String content = matcher.group(2).trim(); 10 String standardAnswer = matcher.group(3).trim(); 11 questionBank.addQuestion(new Question(questionNumber, content, standardAnswer)); 12 } else { 13 System.out.println("wrong format:" + line); 14 } 15 } else if (line.startsWith("#T:")) { 16 Pattern pattern = Pattern.compile("#T:(\\d+)(\\s+\\d+-\\d+)+"); 17 Matcher matcher = pattern.matcher(line); 18 if (matcher.find()) { 19 int paperNumber = Integer.parseInt(matcher.group(1).trim()); 20 Paper paper = new Paper(paperNumber); 21 22 Pattern questionPattern = Pattern.compile("(\\d+)-(\\d+)"); 23 Matcher questionMatcher = questionPattern.matcher(line); 24 while (questionMatcher.find()) { 25 int questionNumber = Integer.parseInt(questionMatcher.group(1).trim()); 26 int score = Integer.parseInt(questionMatcher.group(2).trim()); 27 paper.addQuestion(questionNumber, score); 28 } 29 30 paper.computeTotalScore(); 31 paperBank.addPaper(paper); 32 } else { 33 System.out.println("wrong format:" + line); 34 } 35 } else if (line.startsWith("#X:")) { 36 Pattern pattern = Pattern.compile("#X:((\\d+\\s+\\w+)(-\\d+\\s+\\w+)*)"); 37 Matcher matcher = pattern.matcher(line); 38 if (matcher.find()) { 39 String[] students = matcher.group(1).split("-"); 40 for (String student : students) { 41 String[] studentInfo = student.trim().split(" "); 42 if (studentInfo.length == 2) { 43 studentBank.addStudent(new Student(studentInfo[0].trim(), studentInfo[1].trim())); 44 } else { 45 System.out.println("wrong format:" + line); 46 } 47 } 48 } else { 49 System.out.println("wrong format:" + line); 50 } 51 } else if (line.startsWith("#S:")) { 52 Pattern pattern = Pattern.compile("#S:(\\d+)\\s+(\\d+)((\\s+#A:\\d+-\\d+)*)"); 53 Matcher matcher = pattern.matcher(line); 54 if (matcher.find()) { 55 int paperNumber = Integer.parseInt(matcher.group(1).trim()); 56 String studentId = matcher.group(2).trim(); 57 Paper paper = paperBank.getPaper(paperNumber); 58 if (paper == null) { 59 System.out.println("The test paper number does not exist"); 60 continue; 61 } 62 AnswerPaper answerPaper = new AnswerPaper(paper, studentId); 63 64 Pattern answerPattern = Pattern.compile("#A:(\\d+)-(\\d+)"); 65 Matcher answerMatcher = answerPattern.matcher(line); 66 while (answerMatcher.find()) { 67 answerPaper.addAnswers(answerMatcher.group(2).trim()); 68 } 69 70 answerPaperBank.addAnswerPaper(answerPaper); 71 } else { 72 System.out.println("wrong format:" + line); 73 } 74 } else if (line.startsWith("#D:")) { 75 Pattern pattern = Pattern.compile("#D:N-(\\d+)"); 76 Matcher matcher = pattern.matcher(line); 77 if (matcher.find()) { 78 int questionNumber = Integer.parseInt(matcher.group(1).trim()); 79 questionBank.deleteQuestion(questionNumber); 80 } else { 81 System.out.println("wrong format:" + line); 82 } 83 } else { 84 System.out.println("wrong format:" + line); 85 } 86 } 87 }
- 功能:处理输入并解析成相应的数据结构。
- 逻辑:使用正则表达式匹配不同格式的输入,解析后存储在相应的类中。通过
while
循环持续读取输入,直到遇到 "end"。
逻辑分析
-
循环读取输入:
- 使用
while
循环持续读取输入,直到遇到 "end"。 - 每次读取一行,存储在
line
中。
- 使用
-
处理题目信息 (
#N:
):- 使用正则表达式匹配题目格式:
#N:(\\d+)\\s+#Q:(.*?)\\s+#A:(.*)
- 提取题目编号、内容和标准答案。
- 创建
Question
对象并添加到QuestionBank
。
- 使用正则表达式匹配题目格式:
-
处理试卷信息 (
#T:
):- 使用正则表达式匹配试卷格式:
#T:(\\d+)(\\s+\\d+-\\d+)+
- 提取试卷号和题目编号-分值对。
- 创建
Paper
对象并添加题目和分值。 - 计算总分并存储在
PaperBank
。
- 使用正则表达式匹配试卷格式:
-
处理学生信息 (
#X:
):- 使用正则表达式匹配学生信息格式:
#X:((\\d+\\s+\\w+)(-\\d+\\s+\\w+)*)
- 提取学号和姓名。
- 创建
Student
对象并添加到StudentBank
。
- 使用正则表达式匹配学生信息格式:
-
处理答卷信息 (
#S:
):- 使用正则表达式匹配答卷格式:
#S:(\\d+)\\s+(\\d+)((\\s+#A:\\d+-\\d+)*)
- 提取试卷号、学号和答案。
- 验证试卷是否存在,若不存在则输出错误信息。
- 创建
AnswerPaper
对象,添加答案,并存储在AnswerPaperBank
。
- 使用正则表达式匹配答卷格式:
-
处理删除题目信息 (
#D:
):- 使用正则表达式匹配删除格式:
#D:N-(\\d+)
- 提取题目编号并从
QuestionBank
中删除。
- 使用正则表达式匹配删除格式:
-
格式错误处理:
- 若输入不匹配任何已知格式,输出格式错误提示。
4.2 踩坑心得
(1)删除题目在试卷中总分没有置0
一开始我在解析信息时,每当解析完答卷信息,就计算当前答卷的总分,导致删除题目的总分还未置0就已经计算好了,所以在输出得分情况时,删除题目的分值还是原来的分值,如下图所示:
解决办法就是当解析完答卷信息,不对答卷进行判题,而是在主方法中将所有的答卷进行判题,再输出得分信息,此时得分信息就会正确。
4.3 改进建议
(1)InputHandler.handleInput()
方法的圈复杂度高
handleInput 方法可以通过重构,将其分解为更小、更易管理的方法来降低复杂度,以提高代码可读性和可维护。
(2)在输出时各种情况的输出优先级
需要修改代码将代码修改正确,保证各种境况下输出的优先级正确。
五、总结
在大作业的一次又一次的迭代中,我学到了更多的Java的基础编程知识和面向对象的设计思想,深刻体会到了面向对象设计和模块化编程的重要性。通过合理的封装和功能分离,我不仅提高了代码的可维护性和扩展性,也增强了系统的逻辑性和结构性。这让我更好地理解了单一职责原则和面向对象编程的核心思想。
从第一次大作业的简单输入信息的解析,到后面越来越复杂的输入信息的解析,越来越严格的格式要求,甚至需要对输入信息进行验证,对异常情况进行处理。我在实践中加深了对字符串处理、正则表达式的理解,同时我了解了ArrayList和HashMap集合,并且掌握了对于这些集合的基本操作。
在这三次大作业中我学习到了许多知识,但同样我也发现了我有很多需要改进的地方:代码的独立性不够高导致在迭代的过程中出现对上一次代码的利用率不高;编写代码的时候思绪很容易混乱,大作业写的很艰难缓慢;代码中没有异常处理的机制,代码健壮性不高;平时没有及时跟进学习基础的Java知识。
标签:22207223,trim,题目,matcher,试卷,pta,信息,王颖,line From: https://www.cnblogs.com/PTA-code/p/18500467