第一次博客作业
一、前言:
第一个题目集:
知识点:
包括类的定义、属性(成员变量)、方法(成员函数)以及构造函数。
封装:通过私有化数据域并提供公共的访问器(getter)和修改器(setter)来保护对象内部状态。
构造函数:无参构造函数和带参数构造函数的使用。
字符串表示:重写toString()方法以返回对象的状态信息。
数组与集合:使用数组存储多个对象,并遍历它们进行操作。
关联类:理解一个类如何包含另一个类的对象作为其属性。
输入输出:从用户获取输入,并将结果输出到控制台。
题量:
设计一个风扇Fan类、创建一个学生Student类及其测试、学生成绩计算(基本运用)、学生成绩计算(关联类)、 答题判题程序-1,在当时刚接触java的情况下确实有点多,主要是没教就让写。
难度:
设计一个风扇Fan类:中等难度。需要理解常量、私有数据域、构造函数及自定义的toString()方法。
创建一个学生Student类及其测试:中等难度。除了基本的类设计外,还需要实现对用户的输入处理。
学生成绩计算(基本运用):中等难度。涉及到数组的使用以及简单的数学运算。
学生成绩计算(关联类):较高难度。不仅需要处理成绩计算,还需要处理类之间的关系,即一个类内嵌入了另一个类的对象。
答题判题程序-1:难度高。刚接触java没有那么强的抽象能力,不能又快又精准得抽象出类以及类与类之间得关系,不仅如此,还要自学java自带的封装类数据中自带的方法、java的数组、对象数组、集合容器。
第二个题目集:
知识点:
面向对象编程基础(类、对象、属性、方法)
接口的实现
集合框架的使用
输入输出操作
基本数学运算
题量:
手机按价格排序、查找、求圆的面积(类与对象)、Java类与对象-汽车类、 答题判题程序-2。数量已经能够接受了。
难度:
手机按价格排序、查找:低难度。除了没教接口,没教怎么重写方法,剩下的不用动脑。
求圆的面积(类与对象):低难度。在给出大框架的情况下做代码的填充是相对简单的,但是出题的人是不是语文没学好,简易回去重新学一下语文。
Java类与对象-汽车类:中等难度。给出大框架进行补充,只需要补全没有的方法,在已经知道方法的返回类型以及参数列表的情况下十分简单。
答题判题程序-2:难度高。在第一次的基础上做修改,新增了试卷信息中的分数分布,类与类之间的关系结构也变化了。
第三个题目集:
知识点:
类的设计与封装
构造函数与成员方法
数据验证与异常处理
日期处理和计算
题量:
面向对象编程(封装性)、日期类的基本使用、答题判题程序-3。题目少但是难。
难度:
面向对象编程(封装性):低难度。使用在前面已经学到的知识就能解决问题。
日期类的基本使用:中难度。日期类的学习和使用不难,难得是题目里各种要求。
答题判题程序-3:难度高。在第二题的基础上新增了学号这一属性和其他限制性条件。类与类之间的关系和结构更加复杂了
二、设计与分析:
因为其他题目相较于题目集1~3的最后一题难度太低,在这不做分析。
答题判题程序-1:
类设计
Question (题目类)
属性:
int number: 题目编号
String content: 题目内容
String standardAnswer: 标准答案
方法:
boolean checkAnswer(String answer): 检查给定的答案是否与标准答案匹配
getter 和 setter 方法
Paper (试卷类)
属性:
List
int questionCount: 题目数量
方法:
void addQuestion(Question q): 添加一个新的题目到试卷中
Question getQuestion(int number): 根据题号获取题目
boolean checkAnswer(int number, String answer): 根据题号和答案,检查答案对错
List
AnswerSheet (答卷类)
属性:
Paper paper: 对应的试卷
Map<Integer, String> answers: 答案列表,键为题号,值为答案
Map<Integer, Boolean> results: 判题结果列表,键为题号,值为true/false
方法:
void saveAnswer(int number, String answer): 保存一个题目的答案
void output(): 打印题目及其对应的答案

答题判题程序-2:
判题程序2在一的基础上添加了多张答卷以及题目有分数,答卷的试卷可能是一样的也可能不一样。若继续使用一中高耦合度的代码则会出现数据的冗余以及难修改的坏处。
Question类:
属性: number (题目编号), content (题目内容), standardAnswer (标准答案)
方法: isCorrect(String answer) (检查给定的答案是否正确)
Paper类:
属性: paperNumber (试卷编号), questionScoreMap (题号到分值的映射), totalScore (总分)
方法: addQuestion(int questionNumber, int score) (添加题目及其分值), isFullScoreValid() (检查总分是否为100)
AnswerSheet类:
属性: paperNumber (试卷编号), answers (答案列表)
构造函数: AnswerSheet(int paperNumber, List
答题判题程序-3:
第三题新增学生信息,学生信息和试卷绑定,可以删除题目,题目被删除之后,引用该题目的试卷依然有效,但被删除的题目将以0分计,同时在输出答案时,题目内容与答案改为一条失效提示。

Question类:
属性: number (题目编号), content (题目内容), standardAnswer (标准答案), isValid (题目是否有效)
方法: isCorrect(String answer) (检查给定的答案是否正确), invalidate() (使题目无效), isValid() (检查题目是否有效)
Paper类:
属性: paperNumber (试卷编号), questionScoreMap (题号到分值的映射), totalScore (总分)
方法: addQuestion(int questionNumber, int score) (添加题目及其分值), isFullScoreValid() (检查总分是否为100)
Student类:
属性: studentId (学生ID), name (学生姓名)
构造函数: Student(int studentId, String name)
AnswerSheet类:
属性: paperNumber (试卷编号), studentId (学生ID), answers (答案列表)
构造函数: AnswerSheet(int paperNumber, int studentId, List
逻辑流程
读取输入数据。
根据输入行的前缀(#N:、#T:、#X:、#S:、#D:N-)解析不同的信息类型(题目、试卷、学生、答卷、取消题目)。
将题目存储在questionMap中,试卷存储在paperMap中,学生存储在studentMap中,答卷存储在answerSheets列表中。
对每个答卷进行处理:
检查试卷是否存在。
如果试卷总分不等于100,输出警告。
获取学生的姓名。
遍历试卷中的每道题目,根据答卷中的答案进行判题,并计算分数。
输出每道题目的答题情况及最终得分。
输出学生的成绩。
三、采坑心得:对源码的提交过程中出现的问题及心得进行总结,务必做到详实,拿数据、源码及测试结果说话,切忌假大空
第二次作业我想在第一次的基础上修改,但是我发现因为一张试卷要被多个答卷使用,所以试卷类就不能存放题目类,只能存放分数。题目、试卷、答卷就要在主方法里新建,再根据组合关系进行组合,这样可以提高代码的自由度。
在第三次作业是在第二次作业上修改的,在question类新增isvaild属性,answersheets中的answers类型从list型改成HashMap,这样子提高了取answer时的效率。answersheet类中为了更简单一点,不是存Id而是存一个学生类,因为一张试卷对应一个学生。
第一个题目耦合度太高了,改一个地方,很多地方要改;但是第二次第三次耦合度很低修改类中方法只需要在使用的地方修改使用过程。还有在Main类的主方法中放太多代码了,说明代码还是不够抽象,没有把读入、处理抽象成方法。每次不同题目Main的主方法就要重写一遍,有点偏向面向过程编程了。同时我对java本身自带的对象类数据不够了解,导致我在处理数据时没有使用更优的处理方法。
还有就是最好还是把Main类的主方法中输入输出做处理的代码块做模块化,这样能提高代码健壮性。
四、改进建议:
我觉得pta的答案检测有点死板了,一模一样的输出能提示答案错误。第三次的case6中有错误输入,因为,没把处理模块化,使用正则表达式会很冗杂,所以我使用了try-catch捕捉异常情况,出现异常则保存当前输入,输出结束时在将异常输出。纯纯限制学生思维,学java又不是为了应试教育,解决问题的方法应该是多元化,虽然会有优劣之分,但是这就是学习的意义,学习然后优化。


五、总结:
模块化设计的重要性:
通过将代码分解成多个类和方法,每个部分负责一个具体的职责,这样不仅提高了代码的可读性,也使得维护和扩展变得更加容易。例如,Question、Paper、Student 和 AnswerSheet 类分别封装了题目、试卷、学生和答卷的信息,而Main类则负责整个流程的控制。
异常处理的价值:
在实际开发中,输入数据往往不会总是完美无缺。因此,在解析输入时增加异常处理是非常重要的。这不仅可以帮助我们捕获并处理意外情况,还可以提升程序的健壮性和用户体验。
面向对象编程的优势:
利用面向对象的思想来组织代码,比如使用继承、封装和多态等特性,可以让程序更加灵活。在这个例子中,虽然没有直接体现这些高级特性,但通过定义不同的类和它们之间的关系,已经很好地展示了如何使用面向对象的方法解决问题。
测试的重要性:
虽然在这个简短的示例中没有包含单元测试,但在实际项目中编写测试用例是至关重要的。它可以帮助我们在早期发现错误,并确保代码按预期工作。对于复杂的系统来说,自动化测试尤为重要。