前言
经过三周的Java开发,课程从简单的题目设计逐渐深入复杂的题目逻辑。这三次作业不仅考验了我们对Java语言基础的理解,还涉及了面向对象设计、异常处理、以及复杂数据结构的使用。在写完三次题目集后,也是对这三次进行一个总结,首先题目集的题量是随着不断减少,但是难度不言而喻是逐渐增加的。
第一次作业:主要集中在基础逻辑的实现,侧重于简单的数据输入和输出,但缺乏明确的架构。
第二次作业:开始引入题目判定与试卷结构的概念,这一阶段的挑战是构建合理的架构以确保代码的复用性和可维护性。
第三次作业:显著提升了复杂度,加入了学生信息、答题逻辑的处理、删除题目及错误输入的判定,从而全面考验了我们对代码设计的掌控能力和灵活应对复杂需求的能力。
通过这几周的积累,我们逐步从简单的面向过程编程过渡到了更成熟的面向对象设计,尤其是在处理多个类和数据之间的相互依赖关系时,进一步理解了模块化编程的精髓。虽然这个过程可能比较艰难,但还是努力往这个方向尽力实现。
设计与分析
题目集1采取了分三个类,包括题目,试卷和答卷。
1.Question 类
封装:将题目的编号、内容和标准答案封装在 Question 类中,确保这些属性的访问控制通过私有变量和公有的 getter 方法提供。
构造函数:提供一个构造函数来初始化题目的属性,通过参数直接赋值。
功能方法:实现一个 checkAnswer 方法,该方法用来判断给出的答案是否正确。
返回字符串:重写 toString 方法,以便能够显示题目内容。
2.TestPaper 类
集合管理:TestPaper 类使用 List 来管理所有问题。可以动态地添加问题。
题目检索:提供方法来获取特定编号的题目,支持通过题号检索问题, 使得查询更加高效。
封装设计:保持问题列表的私有性,提供公有方法供外部访问。
3.AnswerSheet 类
答题管理:AnswerSheet 类持有一个 Paper 实例和用户的答案列表,将答案和相应的题目相结合。
评判答案:提供评估答案的方法,该方法遍历每个答案,调用相应的题目对象进行验证。
结果输出:根据评判结果生成输出,使用 printResults 方法将结果打印到控制台,展示题目、用户答案和正确与否的信息。
类图如下:
SourceMonitor报表如下:
总行数为 117 行。这包括所有代码行、空行和注释行,代码中共有 73 条语句,分支语句(如 if、switch 等)占代码的 9.6%,方法调用语句有 28 条,注释行占比为 0%,意味着代码中缺少注释,可能不利于代码的可读性和可维护性, 文件中共有 4 个类或接口,个类平均包含 3.75 个方法,每个方法平均包含 3.00 条语句,表明每个方法相对简单,最复杂方法所在的行是第 94 行,方法是Main,复杂度最高为 4,表示存在较复杂的逻辑分支结构,最深的嵌套块在第 50 行。最大块深度为 4,说明代码中有一定深度的嵌套。平均块深度为 1.78,表示嵌套结构的复杂度适中。通过可视化图表,可以看到,深度为 2 和 3 的语句较多,说明代码嵌套层次主要集中在这两个深度。
题目集2仍是分为三个类但是逻辑上修改了一下,由List转变为哈希表
1.Question 类
代表考试中的一个问题,包含问题的编号、内容和答案,通过构造函数进行初始化。
2.TestPaper 类
代表一个试卷,包含试卷的编号和相关的问题列表(用 HashMap 保存问题编号和对应分数),提供 addQuestion 方法以向试卷中添加问题评分。
3.AnswerSheet 类
代表用户的答案,包含试卷编号和用户提交的答案列表。提供构造函数进行初始化,以及addAnswer方法添加答案。
类图如下:
SourceMonitor报表如下:
总行数为 122 行,代码中共有 86 条语句, 分支语句占比为 11.6%,代码的逻辑分支略有增加。 方法调用语句为 44 条,显示了更多的方法调用。 注释行占比为 1.6%,代码的可读性可能仍较低。文件中包含 4 个类或接口, 每个类平均包含 2.25 个方法 每个方法平均有 7 条语句,显示方法的复杂度和内容有所增加。最复杂方法位于第 88 行。最复杂的方法是 Main.evaluateAnswerSheet()。 最大复杂度为 7,远高于之前的最大复杂度 4,说明存在更复杂的逻辑。 嵌套最深的代码块位于第 44 行。 最大块深度为 4平均块深度为 1.99,可视化图表,主要集中在深度 2 和 3,显示出较多的嵌套结构,深度 4 也有少量分布,说明有一定的代码嵌套。
题目集3相比于题目集2,新增了Student类,所以共有4个类
1.Question类
相比于题目集2没有变化
点击查看代码
class Question {
int number;
String content;
String answer;
public Question(int number, String content, String answer) {
this.number = number;
this.content = content;
this.answer = answer;
}
}
相比于题目集2将totalscore移植到该类,代码如下:
点击查看代码
class TestPaper {
int testNumber;
Map<Integer, Integer> questions = new LinkedHashMap<>();
int totalScore = 0;
public TestPaper(int testNumber) {
this.testNumber = testNumber;
}
public void addQuestion(int questionNumber, int score) {
questions.put(questionNumber, score);
totalScore += score;
}
}
因为多了个Student类,所以相比题目集2,需要多加一个StudentID,代码如下:
点击查看代码
class AnswerSheet {
String testPaperID;
String studentID;
Map<Integer, String> answers = new LinkedHashMap<>();
public AnswerSheet(String testPaperID, String studentID) {
this.testPaperID = testPaperID;
this.studentID = studentID;
}
public void addAnswer(int questionIndex, String answer) {
answers.put(questionIndex, answer);
}
}
表示一个学生,包括学生 ID 和姓名。提供了一个构造函数用于初始化这两个属性,代码如下:
点击查看代码
class Student {
String studentID;
String name;
public Student(String studentID, String name) {
this.studentID = studentID;
this.name = name;
}
}
SourceMonitor报表如下:
行数189,逻辑和功能有所增加,语句数128,语句数量明显增加,表示代码更复杂且实现了更多功能。分支语句占比 21.9%,代码中几乎 1/5 是分支语句,表明包含较多条件逻辑(如 if-else 或 switch 语句)。方法调用语句数63,方法调用进一步增加,表明代码更加依赖于方法的调用来组织逻辑。注释行占比 0.5%注释行占比非常低,虽然文件体量和复杂度都提升,但注释几乎没有,严重影响了代码的可读性和维护性。类的数量比之前4 个类有所增加。每个类的方法数1.40,每个类平均只有 1.4 个方法,比之前的文件减少,这表明类的职责更加单一。每个方法的平均语句数 14.86,每个方法平均包含 14.86 条语句,表明方法体积增大,可能变得更难维护。最复杂方法的位置 第 56 行,最复杂方法名称: Main.main(),主方法的复杂度最高,表明该方法可能负责了大量控制逻辑。最大复杂度30这是一个非常高的复杂度,显示了该方法包含了大量逻辑分支或循环。嵌套最深的块所在行 第 104 行, 最大嵌套深度 6,最大嵌套深度从4 增加到了 6,嵌套变得更复杂,可能影响代码的可读性和调试难度。平均块深度 3.31平均块深度大幅增加,表明大部分代码存在较深的嵌套逻辑。可视化图表分析大部分语句集中在深度 2-4,但也有不少深度达到 5 或 6,这意味着部分代码块的嵌套过于复杂。
踩坑心得
1.在写作业的时候,最令人讨厌的可能就是一些边界的约束,如果只是答案错误还好,至少可以通过测试样例来看到底哪里错了,如果是某一种情况非零返回,比如写第三次大作业时候,十个测试样例,都会显示答案(无论对错),但是交上去会显示有一种情况非零返回,如图所示:
而其他情况都显示答案正确或错误,很容易不知所措。
2.在测试用例3,即有删除题目集的情况
图示并没有考虑删除,而仍对其进行判断应该添加判断删除题目集情况
点击查看代码
if (deletedQuestions.contains(questionNumber)) {
resultOutput.append("the question ").append(questionNumber).append(" invalid~0\n");
}
3.测试样例10的时候,即信息打乱输入,出现了如下情况:
可能没有对打乱输入进行判断,从而导致答案判空。
改进建议
由之前的SourceMonitor表的分析数据也能看出来,就是不爱写注释,可能当时看的时候,思路比较清晰,但是一段时间以后可能就读不太懂了,不利于以后的迭代和阅读,而且一些嵌套用的也比较多,对于理解来说较好理解,但是代码太过冗余,一些复杂度也比较高,应该将代码写的清晰明了,降低复杂度。
总结
从最初简单的逻辑实现,到最终包含题目、试卷、答卷、学生、删除题目等多种输入类型的信息处理,三次作业逐步建立了一个完整的面向对象系统。我们学会了如何通过封装和模块化设计来应对复杂业务逻辑的变化,同时通过抽象和分层设计,使得程序结构更加清晰、可扩展,虽然可能这个过程比较曲折,得分也不是那么高,但是还是要尽力去完成这个事情,还有在作业提交前对测试的覆盖度有时不够,尤其是一些边界情况和格式错误的处理上,未来应注重测试设计,确保程序在各种输入情况下都能稳定运行,做到真正的测试,能够留一些更多的时间去完成大作业。
标签:总结,语句,题目,String,代码,嵌套,方法 From: https://www.cnblogs.com/cxk25/p/18504484