首页 > 编程语言 >面向对象程序设计

面向对象程序设计

时间:2024-10-26 18:21:07浏览次数:1  
标签:题目 试卷 Question 面向对象 答案 程序设计 方法 id

第一次博客作业

一、前言

第一次作业

第一次作业有五道题,前四道为入门及简单的小题,最后一题为难度较大的答题判断程序。主要考察对类的属性和方法的设计与使用,以及在规定格式下对程序用户的输入进行解析从而获取题目、答卷等信息。

第二次作业

第二次作业有四道题,前三道为难度入门的小题,最后一题难度较大,在第一次作业最后一题的基础上添加了试卷类。主要考察对类的属性和方法的设计与使用,以及在规定格式下对程序用户的输入进行进一步的解析从而获取试卷、题目、答卷等信息。

第三次作业

第三次作业有三道题,前两道为难度简单的小题,最后一题难度较大,在第二次作业最后一题的基础上又添加了学生类。主要考察对类的属性和方法的设计与使用,以及在规定格式下对程序用户的输入进行更进一步的解析从而获取试卷、题目、答卷、学生等信息,同时不符合输入格式的输入也会有对应的提示,令人头大(ꐦÒ‸Ó)。

二、设计与分析

第一次作业

SourceMontor报表

image

image

18.6% 的代码行包含注释,1% 的代码行包含类和接口的注释。

平均每个类有 6 个方法,每个方法平均有 7.5 条语句,方法的平均复杂度目标是 15。最大块深度为 3(指代码块嵌套的层数);平均块深度为 1.12;平均复杂度为 3.00(指方法中不同路径的数量,较高的复杂度可能意味着方法难以测试和维护)表明代码的复杂度控制得相对较好。

最复杂的方法是 Main.main(),位于第 55 行。这可能表明 main 方法过于复杂,需要进一步的分解或重构或者需要拆分;其复杂度为 3,包含 15 条语句,最大深度为 3,调用了 8 次方法调用。这表明 main 方法可能需要进一步的优化。

类图

Paper 类包含了多个 Question 对象:
包含一个 List 类型的成员变量 questions,表示试卷中的题目列表。
方法 saveQuestion:接受一个 Question 对象作为参数,并将该对象添加到 questions 列表中。
方法 getQuestions:返回 questions 列表。

Question 类:
包含三个私有成员变量 number、content 和 answer,分别表示题目的编号、内容和标准答案。

Answer 类使用了 Question 对象来打印答案:
包含一个 String[] 类型的成员变量 responses,表示用户的答案。
方法 saveAnswer:接受题目编号和答案作为参数,并将答案存储在 responses 数组中。
方法 getResponse:接受题目编号作为参数,并返回对应的答案。
方法 printAnswer:接受题目编号和 Question 对象作为参数,并打印出题目内容和对应的答案。

Main 类:
包含 main 方法,是程序的入口点。
其使用了 Paper、Question 和 Answer 类。

第二次作业

SourceMontor报表

image

image

19.3% 的代码行包含注释,方法调用语句占总语句的 14.4%,分支语句占总语句的 47%。

平均每个类有 9 个方法,每个方法平均有 8.89 条语句。最大复杂度为 6,这表明有一个方法的复杂度很高。平均块深度为 1.36,表明代码块的平均嵌套层数较低,说明代码结构相对简单。最大块深度为 4(表示代码中最深的嵌套层数),平均复杂度为 3.50,说明方法的平均复杂度处于中等水平。

最复杂的方法是 Main.main(),位于第 87 行,可能需要进一步的优化或重构。Main.main() 方法的复杂度为 6,包含 13 条语句,最大深度为 4,调用了 13 次方法。Main.evaluateAnswerSheet() 方法的复杂度为 1,包含 3 条语句,最大深度为 2,调用了 2 次方法。

类图

image

Question 类:
包含四个成员变量 id、content、answer 和 score,表示一个题目的基本信息和得分。

Paper 类包含了多个 Question 对象:
包含两个成员变量 id 和 questions,表示一个试卷的基本信息和题目分值映射。
包含一个 Map<Integer, Integer> 类型的成员变量 questions,表示试卷中的题目编号和对应分值。

Answer 类使用了 Question 对象来评估答案:
包含两个成员变量 PaperId 和 answers,表示一个答卷的基本信息和答案列表。
包含一个 List 类型的成员变量 answers,表示用户的答案列表。

Main 类:
包含两个静态成员变量 questionBank 和 testPapers来存储 Question 和 Paper 对象,并使用 evaluateAnswerSheet 方法来评估答案。
其使用了 Question、Paper 和 Answer 类。

第三次作业

SourceMontor报表

image

image

14.8% 的代码行包含注释;方法调用语句数 89 个,表明代码的交互性较高;分支语句百分比23.4%。

平均每个类有 10 个方法,每个方法平均有 19 条语句。最大复杂度为 20,这表明有一个方法的复杂度很高。平均块深度为 1.79,表明代码块的平均嵌套层数较低,说明代码结构相对简单。最大块深度为 6,说明方法的平均复杂度处于中等水平。

最复杂的方法是Main.main(),位于176行,可能需要进一步的优化或重构。复杂度为20,包含 57 条语句,调用了 45 次方法,最大深度6,表明代码中存在较深的嵌套结构。

类图

image

Question 类:
包含四个成员变量 id、content、answer 和 isDeleted,表示一个题目的基本信息、答案和删除状态。

点击查看代码
class Question {
    int id; // 题目编号
    String content; // 题目内容
    String answer; // 标准答案
    boolean isDeleted; // 是否被删除

    public Question(int id, String content, String answer) {
        this.id = id;
        this.content = content;
        this.answer = answer;
        this.isDeleted = false;
    }

    // 解析题目信息
    public static Question parseFromInput(String input) throws Exception {
        // 格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
        // 过程略
        return new Question(id, content, answer);
    }
}

Paper 类:
包含三个成员变量 id、questionIdToScore 和 sequenceToQuestionId,表示一个试卷的基本信息、题目分值映射和题目顺序。
包含一个 LinkedHashMap<Integer, Integer> 类型的成员变量 questionIdToScore,表示试卷中的题目编号和对应分值。
包含一个 LinkedHashMap<Integer, Integer> 类型的成员变量 sequenceToQuestionId,表示试卷中的题目顺序和题目编号。

点击查看代码
class Paper {
    int id; // 试卷编号
    LinkedHashMap<Integer, Integer> questionIdToScore; // 题目编号 -> 分值,保持输入顺序
    LinkedHashMap<Integer, Integer> sequenceToQuestionId; // 顺序号 -> 题目编号

    public Paper(int id) {
        this.id = id;
        this.questionIdToScore = new LinkedHashMap<>();
        this.sequenceToQuestionId = new LinkedHashMap<>();
    }

    // 解析试卷信息
    public static Paper parseFromInput(String input) throws Exception {
        // 格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值+" "+...
        // 过程略
        return paper;
    }

    // 计算试卷总分
    public int getTotalScore() {
        int total = 0;
        for (int score : questionIdToScore.values()) {
            total += score;
        }
        return total;
    }
}

Student 类:
包含两个成员变量 id 和 name,表示学生的基本信息。

点击查看代码
class Student {
    String id; // 学号
    String name; // 姓名

    public Student(String id, String name) {
        this.id = id;
        this.name = name;
    }

    // 解析学生信息
    public static List<Student> parseFromInput(String input) throws Exception {
        // 格式:"#X:"+学号+" "+姓名+"-"+学号+" "+姓名+...
        // 过程略
        return students;
    }
}

AnswerSheet 类:
使用了 Paper 和 Student 对象来表示答卷信息。包含三个成员变量 paperId、studentId 和 sequenceToAnswer,表示一个答卷的基本信息、学生答案和题目顺序。
包含一个 LinkedHashMap<Integer, String> 类型的成员变量 sequenceToAnswer,表示答卷中的题目顺序和学生答案。

点击查看代码
class AnswerSheet {
    int paperId; // 试卷编号
    String studentId; // 学号
    LinkedHashMap<Integer, String> sequenceToAnswer; // 顺序号 -> 答案

    public AnswerSheet(int paperId, String studentId) {
        this.paperId = paperId;
        this.studentId = studentId;
        this.sequenceToAnswer = new LinkedHashMap<>();
    }

    // 解析答卷信息
    public static AnswerSheet parseFromInput(String input) throws Exception {
        // 格式:"#S:"+试卷号+" "+学号+" "+"#A:"+顺序号+"-"+答案+" "+...
        // 过程略
        return sheet;
    }
}

Main 类:
包含 main 方法,是程序的入口点,包含数据存储结构和业务逻辑。
使用 HashMap、LinkedHashMap 和 ArrayList 来存储 Question、Paper、Student 和 AnswerSheet 对象。

三、踩坑与心得

前三次作业都在PTA平台上面提交,在提交时我遇到了一系列以下问题:

1.逻辑错误

逻辑错误往往比较好纠正,比如在解析用户输入内容时的分类:

4、答卷信息
答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序号与试 卷信息中的题目顺序相对应。答卷中:
格式:"#S:"+试卷号+" "+学号+" "+"#A:"+试卷题目的顺序号+"-"+答案内容+...

上述引用自第三次作业最后一题的题目的要求之一,要求程序在读到"#S:"时后面跟着试卷号以及学生的学号,而读到"#A:"时后面就跟着试卷题目的顺序号以及该学生的答案。需认真审题,避免因读题不完整而产生逻辑错误。

2.答案错误

答案错误往往是计算逻辑错误或者输出的格式有误。前者已经提及,而后者经常出现在一些细小的地方,往往是某个地方缺少或者多余了一个空格这般,这时需要用到平台自带的测试用例进行运行测试,通过比对预计输出以及实际输出的不同找出格式错误。
还有一大类是在第三次作业当中普遍出现的,即对于警告的输出。第三次作业添加了多种警告提醒,各个警示之间还存在优先级,令人十分头大_(:3 ⌒゙)_:

1、试卷总分警示
该部分仅当一张试卷的总分分值不等于100分时作提示之用,试卷依然属于正常试卷,可用于后面的答题。如果总分等于100 分,该部分忽略,不输出。
格式:"alert: full score of test paper" + 试卷号 + " is not 100 points"
2、答卷信息
如果输入的答案信息少于试卷的题目数量,缺失答案的题目输出
格式:"answer is null" 。
3、被删除的题目提示信息
当某题目被试卷引用,同时被删除时,答案中输出提示信息
格式:"the question" + 题目号 + "invalid~0"
4、题目引用错误提示信息
试卷错误地引用了一道不存在题号的试题,在输出学生答案时提示
格式:"non-existent question~"加答案。
如果答案输出时,一道题目同时出现答案不存在、引用错误题号、题目被删除,只提示一种信息,答案不存在的优先级最高:
6、格式错误提示信息
输入信息只要不符合格式要求输出
格式:"wrong format:" + 信息内容。
7、试卷号引用错误提示输出
如果答卷信息中试卷的编号找不到时输出
格式:"the test paper number does not exist",答卷中的答案不用输出
8、学号引用错误提示信息
如果答卷中的学号信息不在学生列表中,答案照常输出,判分时提示
格式:学号 + "not found"

上述引用自第三次作业最后一题的题目的题干,而对于各种警示的则需要考虑每一种输入情况,再通过优先级的不同依次提醒,该过程依旧需要用到平台自带的测试用例进行运行测试,通过比对预计输出以及实际输出的不同找出错误。

3.非零返回

非零返回这一问题困扰了我许久许久,导致前两次作业不太理想,主要是不理解非零返回到底指什么(甚至还有过在main的最后添加"return 0"这一天真的做法:P)
于是我查找资料,到底什么是非零返回,得到的答案是这样的:

在PTA平台上提交代码时,出现“非零返回”错误通常意味着程序在运行过程中遇到了异常情况,导致返回状态码不是零。

然并卵:)还是没说清楚什么是"返回状态码不是零",接着我继续查导致的原因,总结了以下几点:
一、逻辑错误:
描述:程序中的逻辑错误可能导致某些条件未被满足,结果抛出未捕获的异常或进入死循环。
解决方法:仔细检查代码逻辑,确保所有条件都被正确处理。使用调试器逐步执行代码,观察变量的变化,确定导致异常的具体位置和原因。

二、数组或列表越界:
描述:访问数组或列表时,索引超出范围。
解决方法:在访问数组或列表之前,检查索引是否在合法范围内。

三、非零返回值:
描述:程序中调用了System.exit()并传递了非零值。
解决方法:避免直接调用System.exit(),让程序自然结束以确保返回值为0。

四、输入输出错误:
描述:如尝试读取不存在的文件或将数据写入只读的文件。
解决方法:对输入数据进行有效性检查,确保在处理之前数据的合法性。

我一条一条比对时发现,基本上都是第四种情况,说人话即输入的格式错误导致用户输入为空或不符合预期格式,然而,PTA检测时的输入是固定的,所以还是代码在解析用户输入时有的清理没有考虑到(所以仔细审题就可以解决所有的问题吗)། – _ – །། – _ – །། – _ – །

四、改进建议及总结

改进建议:我认为测试用例可以再多一点,最好是每一个测试点都能有个测试用例:
image
比如第三次作业的最后一题,改了半天最后两个测试点都过不去(就差这6分就满分了:-C)如果能够给出详细的测试用例,就可以根据预计输出以及实际输出的不同找出哪里还需要修改,而这个测试用例也可以非常直观的显示出来。

总结:通过本阶段三次题目集的编写以及提交,我在面向对象的思想上有了进一步的了解,学会了许多JAVA的语法函数。但对于一些相关方法还需要进一步学习及研究,希望上课时能更多的了解这方面的内容。

标签:题目,试卷,Question,面向对象,答案,程序设计,方法,id
From: https://www.cnblogs.com/yangjiaobaoza/p/18502875

相关文章