前言
这学期刚刚接触面向对象程序设计,使用的是java语言。在此之前只接触过c语言。以我目前的学习进程来看二者的差别更多体现在面向对象的其中一个基本特性上,即封装性。在c语言中几乎所有内容都是公开的,java可以有效得规避这点。
学习的知识点
1.知道了类间关系。面向对象程序设计中要根据实际情况合理使用继承,关联,聚合,组合,依赖等五类类间关系。选择合适的类间关系有利于代码的维护和使用。
2.知道了类的使用。类可以包含属性和方法。这使得类可以实现单一职责原则。这项原则在程序设计中尤为重要。另外的,设计类时也要注意封装性,不能盲目得使用public。同时,部分类需要通过实例调用。
3.学习了java包中的部分方法,知道了导包。为了完成PTA作业,学习了regex,Math等包中的方法,便于处理部分问题。
4.学会了管理数据。学习了ArrayList,LinkedList和HashMap的原理和使用。
自我改进的方面
- 增强程序设计的“全局观念”。设计程序考虑后续的拓展与维护。
- 拓宽学习方法。对于面向对象的学习不能仅局限于学校的学习体系,学习网站和AI大模型也是较好的学习途径。
三次PTA的难度逐步加大的同时也根据实际情况增加了越来越多的限制,对学生的应变能力与自学能力有较大要求。
设计分析
第一次PTA大作业:
1)题目要求
7-5 答题判题程序-1
分数 74
困难
作者 蔡轲
单位 南昌航空大学
设计实现答题程序,模拟一个小型的测试,要求输入题目信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分三部分:
1、题目数量
格式:整数数值,若超过1位最高位不能为0,
样例:34
2、题目内容
一行为一道题,可以输入多行数据。
格式:"#N:"+题号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
样例:#N:1 #Q:1+1= #A:23、答题信息
答题信息按行输入,每一行为一组答案,每组答案包含第2部分所有题目的解题答案,答案的顺序号与题目题号相对应。
格式:"#A:"+答案内容
格式约束:答案数量与第2部分题目的数量相同,答案之间以英文空格分隔。
样例:#A:2 #A:78- 2是题号为1的题目的答案
- 78是题号为2的题目的答案
复制代码 答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、题目数量
格式:整数数值,若超过1位最高位不能为0,
样例:34
2、答题信息
一行为一道题的答题信息,根据题目的数量输出多行数据。
格式:题目内容+" ~"+答案
样例:1+1=~23、判题信息
判题信息为一行数据,一条答题记录每个答案的判断结果,答案的先后顺序与题目题号相对应。
格式:判题结果+" "+判题结果
格式约束:- 1、判题结果输出只能是true或者false,
- 2、判题信息的顺序与输入答题信息中的顺序相同
复制代码 样例:true false true
设计建议:
以下是针对以上题目要求的设计建议,其中的属性、方法为最小集,实现代码中可根据情况添加所需的内容:
题目类(用于封装单个题目的信息):
属性:题目编号、题目内容、标准答案-standardAnswer
方法:数据读写set\get方法、
判题方法(答案-answer):判断答案-answer是否符合标准答案-standardAnswer
试卷类(用于封装整套题目的信息)
属性:题目列表(题目类的对象集合)、题目数量
方法:判题方法(题号-num、答案-answer):判断答案-answer是否符合对应题号的题目标准答案-standardAnswer
保存题目(题号-num、题目-question):将题目保存到题目列表中,保存位置与num要能对应
答卷类(用于封装答题信息)
属性:试卷(试卷类的对象)、答案列表(保存每一题的答案)、判题列表(保存每一题的判题结果true/false)
方法:判题方法(题号-num):判断答案列表中第num题的结果是否符合试卷中对应题号的题目标准答案
输出方法(题号-num):按照题目的格式要求,输出题号为num的题目的内容和答题结果。
保存一个答案(题号-num,答案-answer):保存题号为num的题目的答题结果answer。
2)个人设计
由于第一次作业给出了设计建议,本次作业按照建议进行设计。
针对题目信息设计了exercise类,其中包含了题号,题目内容和正确答案三个属性。除构造方法等存取类方法外,还设计了一个根据输入的答案判断答案对错的方法。
`class exercise{
private int NO = 0;//题号
private String Content = "";//题目内容
private String standardAnswer = "";//正确答案- public int getNO() {
- return NO;
- }
- public void setNO(int NO) {
- this.NO = NO;
- }
- public String getContent() {
- return Content;
- }
- public void setContent(String content) {
- Content = content;
- }
- public String getStandardAnswer() {
- return standardAnswer;
- }
- public void setStandardAnswer(String standardAnswer) {
- this.standardAnswer = standardAnswer;
- }
- public boolean judge(String answer){//判断对错
- return answer.equals(this.standardAnswer);
- }
复制代码 }`
针对试卷信息设计了paper类,其中包含了总题数和题目类数组两个属性。除构造方法等存取类方法外,还设计了一个根据题目顺序和答案判断对应题目的答案的对错的方法。
`class paper {
public int sum;//总题数
public exercise[] exe;//题目数组- public boolean Judge(int num, String answer) {
- return exe[num].judge(answer);
- }
- public void save(int num, String question) {
- exe[num].setNO(num);
- exe[num].setContent(question);
- }
- public int getSum() {
- return sum;
- }
- public void setSum(int sum) {
- this.sum = sum;
- exe = new exercise[sum + 1];
- }
复制代码 }`
针对答卷信息设计了AnswerPaper类,其中包含了试卷,答案列表和判断列表三个属性。只有存取类方法。
`class AnswerPaper {
public paper Paper;//试卷
private String[] answer;//答案列表
private boolean[] judge;//判断列表- public AnswerPaper(int sum) {
- this.answer = new String[sum + 1];
- this.judge = new boolean[sum + 1];
- }
- public void judge(int num) {
- this.judge[num] = Paper.exe[num].judge(answer[num]);
- }
- public void saveAnswer(int num, String answer) {
- this.answer[num] = answer;
- }
- public void setPaper(paper paper) {
- Paper = paper;
- }
- public void setAnswer(String[] answer) {
- this.answer = answer;
- }
- public void setJudge(boolean[] judge) {
- this.judge = judge;
- }
- public String[] getAnswer() {
- return answer;
- }
- public boolean[] getJudge() {
- return judge;
- }
复制代码 }`
3)设计分析:
由于本次作业是第一次大作业,本人对于程序设计经验欠缺,造成了较大的设计缺陷:
- 设计的类中部分属性为public,这不符合面向对象的封装性。
- 没有考虑程序的后续迭代,部分类设计仅适用于当前作业,而在后续作业无法继续使用。如因为本题给出了总题数,在paper类设计中就简单得将题目存在以总题数为长度的数组中,没有考虑到后续题目数量的确定和试卷中题目的顺序。
第二次PTA大作业
1)题目要求
7-4 答题判题程序-2
分数 73
困难
作者 蔡轲
单位 南昌航空大学
设计实现答题程序,模拟一个小型的测试,以下粗体字显示的是在答题判题程序-1基础上增补或者修改的内容。
要求输入题目信息、试卷信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分三种,三种信息可能会打乱顺序混合输入:
1、题目信息
一行为一道题,可输入多行数据(多道题)。
格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:- 1、题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
- 2、允许题目编号有缺失,例如:所有输入的题号为1、2、5,缺少其中的3号题。此种情况视为正常。
复制代码 样例:#N:1 #Q:1+1= #A:22、试卷信息
一行为一张试卷,可输入多行数据(多张卷)。
格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值- 题目编号应与题目信息中的编号对应。
- 一行信息中可有多项题目编号与分值。
复制代码 样例:#T:1 3-5 4-8 5-2
3、答卷信息- 答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序与试卷信息中的题目顺序相对应。
复制代码 格式:"#S:"+试卷号+" "+"#A:"+答案内容
格式约束:答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
样例:#S:1 #A:5 #A:22- 1是试卷号
- 5是1号试卷的顺序第1题的题目答案
- 22是1号试卷的顺序第2题的题目答案
复制代码 答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、试卷总分警示
该部分仅当一张试卷的总分分值不等于100分时作提示之用,试卷依然属于正常试卷,可用于后面的答题。如果总分等于100分,该部分忽略,不输出。
格式:"alert: full score of test paper"+试卷号+" is not 100 points"
样例:alert: full score of test paper2 is not 100 points
2、答卷信息
一行为一道题的答题信息,根据试卷的题目的数量输出多行数据。
格式:题目内容+""+答案++""+判题结果(true/false)
约束:如果输入的答案信息少于试卷的题目数量,答案的题目要输"answer is null"
样例:3+2=5true- 4+6=~22~false.
- answer is null
复制代码 3、判分信息
判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。
格式:题目得分+" "+....+题目得分+"~"+总分
``
格式约束:
1、没有输入答案的题目计0分
2、判题信息的顺序与输入答题信息中的顺序相同
样例:5 8 0~13
根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。
4、提示错误的试卷号
如果答案信息中试卷的编号找不到,则输出”the test paper number does not exist”,参见样例9。
设计建议:
参考答题判题程序-1,建议增加答题类,类的内容以及类之间的关联自行设计。
题目相当于第一次作业更加复杂:
- 输入的三种信息可以乱序混合输入
- 由一张试卷演变成了多张试卷,每张试卷信息都需要存储
- 存在答卷没有答案或多余答案的情况
- 新增试卷总分预警
- 空答案的答卷有单独的输出情况
- 新增了判分信息的输出
2)个人设计
针对题目类,本次作业整体延用了上次作业的exercise类
`class exercise{
private int NO;//题目编号
private String Content;//题目内容
private String standardAnswer;//正确答案- public exercise(int NO, String content, String standardAnswer) { this.NO = NO; Content = content; this.standardAnswer = standardAnswer;}public int getNO() {
- return NO;
- }
- public void setNO(int NO) {
- this.NO = NO;
- }
- public String getContent() {
- return Content;
- }
- public void setContent(String content) {
- Content = content;
- }
- public String getStandardAnswer() {
- return standardAnswer;
- }
- public void setStandardAnswer(String standardAnswer) {
- this.standardAnswer = standardAnswer;
- }
- public boolean judge(String answer){//判断对错
- return answer.equals(this.standardAnswer);
- }
复制代码 }`
针对试卷类,本次作业与上次相比变化较大。有试卷编号,题目号与分值组成的HashMap,试卷总分和存储试卷号顺序的ArrayList。使用HashMap是为了将题目编号与题目分值相关联;使用ArrayList是因为本次作业未给出试卷的题目总数;试卷总分是为了实现试卷总分预警。
`class paper {
private static int NoPaper;//试卷编号
private HashMap ExerciseAndGrade;// key为题目编号,value为题目分值
private int SumGrade = 0;
private ArrayList EXES = new ArrayList();//试卷题号顺序- public paper(int noPaper) {
- NoPaper = noPaper;
- ExerciseAndGrade = new HashMap<>(); // 初始化ExerciseAndGrade
- }
- public void setExerciseAndGrade(int NOEXE, int Grade) {
- ExerciseAndGrade.put(NOEXE, Grade);
- SumGrade = SumGrade + Grade;
- }
- public ArrayList<Integer> getEXES() {
- return EXES;
- }
- public void addEXES(int NO) {
- EXES.add(NO);
- }
- public int getSumGrade() {
- return SumGrade;
- }
- public HashMap<Integer, Integer> getExerciseAndGrade() {
- return ExerciseAndGrade;
- }
复制代码 }`
针对答卷类,本次作业对其进行了重新设计。设计了答卷编号和存储答案的ArrayList两个属性。使用ArrayList是因为本次作业未给出试卷的总题目数。
`class AnswerPaper {
private int _NoPaper;//答卷编号
private ArrayList Answers;//答案的数组- public AnswerPaper(int _NoPaper) {
- this._NoPaper = _NoPaper;
- Answers = new ArrayList<>(); // 初始化Answers
- }
- public void setAnswer(String Answer) {
- Answers.add(Answer);
- }
- public int get_NoPaper() {
- return _NoPaper;
- }
- public void set_NoPaper(int _NoPaper) {
- this._NoPaper = _NoPaper;
- }
- public ArrayList<String> getAnswers() {
- return Answers;
- }
- public void setAnswers(String answers) {
- Answers.add(answers);
- }
复制代码 }`
在Main类中定义了存储题号和题目实例的exerciseMap,为HashMap;存储试卷编号与试卷实例的PaperMap,为HashMap;存储试卷编号的PaperSum,为ArrayList;存储答卷实例的answerPaper,为ArrayList。
//题目类 static HashMap exerciseMap=new HashMap();//key题号,value题目 //试卷类 static HashMap PaperMap=new HashMap(); //key编号 value试卷 static ArrayList PaperSum = new ArrayList();//存试卷编号 //答卷类 static ArrayList answerPaper=new ArrayList();//答卷的数组
在main方法中对于输入数据的处理与上次作业有较大不同。
由于输入格式的改变,输入时先对输入数据关键字进行匹配与分类,根据不同的类别处理信息。
`String Str = "";
while (sc.hasNextLine()) {
Str = sc.nextLine();
if(Str.equals("end")) {
break;
}
if(Str.contains("#N")){
String[] parts = Str.split("#N:| #Q:| #A:");
exercise EXE = new exercise(Integer.parseInt(parts[1]),parts[2],parts[3]);
exerciseMap.put(Integer.parseInt(parts[1]),EXE);
[code] } else if (Str.contains(("#T"))) { String[] parts = Str.split("#T:|-| "); paper PAPER = new paper(Integer.parseInt(parts[1])); for(int i = 2;i < parts.length;i = i + 2) { PAPER.setExerciseAndGrade(Integer.parseInt(parts),Integer.parseInt(parts[i + 1])); PAPER.getEXES().add(Integer.parseInt(parts)); } PaperMap.put(Integer.parseInt(parts[1]),PAPER); if(!PaperSum.contains(Integer.parseInt(parts[1]))) { PaperSum.add(Integer.parseInt(parts[1])); } } else if(Str.contains("#S")){ String[] parts = Str.split("#S:| #A:"); AnswerPaper Anpaper = new AnswerPaper(Integer.parseInt(parts[1])); for(int i = 2; i |