oop第一次博客作业
前言
这学期刚刚接触面向对象程序设计,使用的是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:2
#N:2 #Q:2+2= #A:4
3、答题信息
答题信息按行输入,每一行为一组答案,每组答案包含第2部分所有题目的解题答案,答案的顺序号与题目题号相对应。
格式:"#A:"+答案内容
格式约束:答案数量与第2部分题目的数量相同,答案之间以英文空格分隔。
样例:#A:2 #A:78
2是题号为1的题目的答案
78是题号为2的题目的答案
答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、题目数量
格式:整数数值,若超过1位最高位不能为0,
样例:34
2、答题信息
一行为一道题的答题信息,根据题目的数量输出多行数据。
格式:题目内容+" ~"+答案
样例:1+1=~2
2+2= ~4
3、判题信息
判题信息为一行数据,一条答题记录每个答案的判断结果,答案的先后顺序与题目题号相对应。
格式:判题结果+" "+判题结果
格式约束:
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:2
#N:2 #Q:2+2= #A:4
2、试卷信息
一行为一张试卷,可输入多行数据(多张卷)。
格式:"#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<Integer, Integer> ExerciseAndGrade;// key为题目编号,value为题目分值
private int SumGrade = 0;
private 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
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<Integer,exercise> exerciseMap=new HashMap<>();//key题号,value题目 //试卷类 static HashMap<Integer,paper> PaperMap=new HashMap<>(); //key编号 value试卷 static ArrayList<Integer> PaperSum = new ArrayList<>();//存试卷编号 //答卷类 static ArrayList<AnswerPaper> 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);
} 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[i]),Integer.parseInt(parts[i + 1]));
PAPER.getEXES().add(Integer.parseInt(parts[i]));
}
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 <= parts.length - 1;i ++){
Anpaper.setAnswer(parts[i]);
}
answerPaper.add(Anpaper);
}
}`
3)设计分析
- 吸取上次作业的教训,本次作业对所有属性都进行了封装。
- 由于不知道各类信息的具体数量,本次作业灵活使用ArrayList处理数据。同时,对于部分有联系的信息采用了HashMap进行存储。
- 各类基本实现了单一职责。
- 对于上次作业的结构进行了较大改变,使其符合题目要求的同时更好得进行拓展。
第三次PTA大作业
1)题目要求
7-3 答题判题程序-3
分数 84
困难
作者 蔡轲
单位 南昌航空大学
设计实现答题程序,模拟一个小型的测试,以下粗体字显示的是在答题判题程序-2基础上增补或者修改的内容,要求输入题目信息、试卷信息、答题信息、学生信息、删除题目信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分五种,信息可能会打乱顺序混合输入。
1、题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。
格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:
1、题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
2、允许题目编号有缺失,例如:所有输入的题号为1、2、5,缺少其中的3号题。此种情况视为正常。
样例:#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
2、试卷信息
试卷信息为独行输入,一行为一张试卷,多张卷可分多行输入数据。
格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值+" "+题目编号+"-"+题目分值+...
格式约束:
题目编号应与题目信息中的编号对应。
一行信息中可有多项题目编号与分值。
样例:#T:1 3-5 4-8 5-2
3、学生信息
学生信息只输入一行,一行中包括所有学生的信息,每个学生的信息包括学号和姓名,格式如下。
格式:"#X:"+学号+" "+姓名+"-"+学号+" "+姓名....+"-"+学号+" "+姓名
格式约束:
答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
样例:
#S:1 #A:5 #A:22
1是试卷号
5是1号试卷的顺序第1题的题目答案
4、答卷信息
答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序号与试 卷信息中的题目顺序相对应。答卷中:
格式:"#S:"+试卷号+" "+学号+" "+"#A:"+试卷题目的顺序号+"-"+答案内容+...
格式约束:
答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
答案内容可以为空,即””。
答案内容中如果首尾有多余的空格,应去除后再进行判断。
样例:
#T:1 1-5 3-2 2-5 6-9 4-10 7-3
#S:1 20201103 #A:2-5 #A:6-4
1是试卷号
20201103是学号
2-5中的2是试卷中顺序号,5是试卷第2题的答案,即T中3-2的答案
6-4中的6是试卷中顺序号,4是试卷第6题的答案,即T中7-3的答案
注意:不要混淆顺序号与题号
5、删除题目信息
删除题目信息为独行输入,每一行为一条删除信息,多条删除信息可分多行输入。该信息用于删除一道题目信息,题目被删除之后,引用该题目的试卷依然有效,但被删除的题目将以0分计,同时在输出答案时,题目内容与答案改为一条失效提示,例如:”the question 2 invalid~0”
格式:"#D:N-"+题目号
格式约束:
题目号与第一项”题目信息”中的题号相对应,不是试卷中的题目顺序号。
本题暂不考虑删除的题号不存在的情况。
样例:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack
S:1 20201103 #A:1-5 #A:2-4
D:N-2
end
输出
alert: full score of test paper1 is not 100 points
1+1=5false
the question 2 invalid~0
20201103 Tom: 0 0~0
答题信息以一行"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=22false.
answer is null
3、判分信息
判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。
格式:**学号+" "+姓名+": "**+题目得分+" "+....+题目得分+"~"+总分
格式约束:
1、没有输入答案的题目、被删除的题目、答案错误的题目计0分
2、判题信息的顺序与输入答题信息中的顺序相同
样例:20201103 Tom: 0 0~0
根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。
4、被删除的题目提示信息
当某题目被试卷引用,同时被删除时,答案中输出提示信息。样例见第5种输入信息“删除题目信息”。
5、题目引用错误提示信息
试卷错误地引用了一道不存在题号的试题,在输出学生答案时,提示”non-existent question~”加答案。例如:
输入:
N:1 #Q:1+1= #A:2
T:1 3-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-4
end
输出:
alert: full score of test paper1 is not 100 points
non-existent question~0
20201103 Tom: 0~0
如果答案输出时,一道题目同时出现答案不存在、引用错误题号、题目被删除,只提示一种信息,答案不存在的优先级最高,例如:
输入:
N:1 #Q:1+1= #A:2
T:1 3-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103
end
输出:
alert: full score of test paper1 is not 100 points
answer is null
20201103 Tom: 0~0
6、格式错误提示信息
输入信息只要不符合格式要求,均输出”wrong format:”+信息内容。
例如:wrong format:2 #Q:2+2= #4
7、试卷号引用错误提示输出
如果答卷信息中试卷的编号找不到,则输出”the test paper number does not exist”,答卷中的答案不用输出,参见样例8。
8、学号引用错误提示信息
如果答卷中的学号信息不在学生列表中,答案照常输出,判分时提示错误。参见样例9。
本题暂不考虑出现多张答卷的信息的情况。
题目在上次作业的基础上进行迭代:
- 新增了删除题目信息。被删除的题目有单独的输出方法。
- 新增了学生信息,需要单独存储。
- 答卷信息中新增了学生学号的属性。
- 存在题目引用错误的情况。
- 答卷的题目与试卷题目顺序相对应。
2)个人设计
题目类与上次作业相比变化不大
`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);
}
}`
试卷类与上次作业相比变化不大
`class paper {
private static int NoPaper;//试卷编号
private HashMap<Integer, Integer> ExerciseAndGrade;// key为题目编号,value为题目分值
private int SumGrade = 0;
private 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。答案顺序属性是为了适应改变的要求。
`class AnswerPaper {
private int _NoPaper;//答卷编号
private HashMap<Integer,String> Answers;//key为答卷的试卷题目顺序号,value为答案 // 答案的数组
private int AnswerStuID;
private ArrayList
public AnswerPaper(int _NoPaper) {
this._NoPaper = _NoPaper;
Answers = new HashMap<>(); // 初始化Answers
AnswerOrder = new ArrayList<>();
}
public void setAnswer(int NO,String Answer) {
Answers.put(NO,Answer);
}
public int get_NoPaper() {
return _NoPaper;
}
public void set_NoPaper(int _NoPaper) {
this._NoPaper = _NoPaper;
}
public HashMap<Integer, String> getAnswers() {
return Answers;
}
public void setAnswers(int NO,String answers) {
Answers.put(NO,answers);
}
public int getAnswerStuID() {
return AnswerStuID;
}
public void setAnswerStuID(int answerStuID) {
AnswerStuID = answerStuID;
}
public ArrayList<Integer> getAnswerOrder() {
return AnswerOrder;
}
public void AnswerOrderAdd(int NO) {
AnswerOrder.add(NO);
}
}`
针对学生信息,新增学生类。包含学生学号与学生姓名两个属性。只有基本的存取方法。
`class student {
private int studentID;
private String name;
public student(int studentID, String name) {
this.studentID = studentID;
this.name = name;
}
public student() {
}
public int getStudentID() {
return studentID;
}
public void setStudentID(int studentID) {
this.studentID = studentID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}`
针对删除题目信息,新增删除题目类。因为被删除题目在后续也需要输出相关的题目信息,不能直接将其删除,使用新增类来存储信息。删除题目信息类只包含被删除题目的题号一个属性和基本的存取方法。
`class exerciseBeDeleted {
int delNO;
public exerciseBeDeleted(int delNO) {
this.delNO = delNO;
}
public int getDelNO() {
return delNO;
}
public void setDelNO(int delNO) {
this.delNO = delNO;
}
}`
考虑到题目需要判断输入信息是否有效,新增判断信息是否有效类。包含所需判断的信息一个属性和各种输入方法有效性判断的方法。
`class judgevalid {
private String input;
public judgevalid(String input) {
this.input = input;
}
public String getInput() {
return input;
}
public boolean exerciseValid() {
String regex = "^#N:\\d+ #Q:.* #A:.*$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public boolean paperValid() {
String regex = "^#T:\\d+(( \\d+-\\d+)+)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public boolean studentValid() {
String regex = "^#X:((\\d+) ((\\w+)-(\\d+))+ (\\w+))";//-(\\\\d+) (\\\\w+)(?:-\\\\d+ \\\\w+)*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return true;
//return matcher.matches();
}
public boolean answerPaperValid() {
String regex = "^#S:\\d+ \\d+( #A:\\d*-[^\\s]*)*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public boolean delExeValid() {
String regex = "#D:N-\\d+$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
}`
为了符合题目要求,在Main方法中增加以下方法
- 判断题目是否被删除的方法。
public static boolean ExeBeDel(int EXENO) { for(int i = 0;i < delEXE.size();i ++) { if(delEXE.get(i).getDelNO() == EXENO) { return true; } } return false; }
- 精确获得学生信息在数组中位置的方法。
public static int AnStuID(int ID,ArrayList<student> Stu) { for(int i = 0;i < Stu.size();i ++) { if(Stu.get(i).getStudentID() == ID) { return i; } } return -1; }
在Main方法中增加了存储学生实例的studentList,为ArrayList和存储删除题目实例的delEXE,为ArrayList
//学生数组 static ArrayList<student>studentList = new ArrayList<>(); //删除的题目类 static ArrayList<exerciseBeDeleted> delEXE = new ArrayList<>();//被删除的题目的数组
3)设计分析
- 本次作业在上次作业延用的基础上再拓展。
- 在Main类里设计方法,使逻辑更清晰。
踩坑心得
- 在第一次作业中,程序的结构设计较差,程序只适用于当前作业,导致后续作业需要重新设计,造成巨大麻烦。日后的程序设计需要先设计好结构。
- 在第一次作业中没有对类的属性进行封装。日后程序设计要考虑封装性。
- 在第二次和第三次作业中数据的获取调用太多方法,显得过于冗长难以辨别。日后可以通过设计方法来统一进行部分数据的获取。
for(int j = 0; j < PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().size(); j ++) { //j小于对应答卷的题目数时 if(answerPaper.get(i).getAnswers().size() < j + 1) { System.out.println("answer is null"); } else { System.out.printf("%s~%s~%s\n",exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j)).getContent(),answerPaper.get(i).getAnswers().get(j),exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j)).judge(answerPaper.get(i).getAnswers().get(j))); } }//答卷的试卷号匹配题目号,题目号匹配题目和答案
改进建议
1. 部分重复冗长的方法调用,尝试编写方法解决。
如以下部分可以设计方法获取需要的值
for(int j = 0; j < PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().size(); j ++) { //j小于对应答卷的题目数时 if(answerPaper.get(i).getAnswers().size() < j + 1) { System.out.println("answer is null"); } else { System.out.printf("%s~%s~%s\n",exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j)).getContent(),answerPaper.get(i).getAnswers().get(j),exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j)).judge(answerPaper.get(i).getAnswers().get(j))); } }//答卷的试卷号匹配题目号,题目号匹配题目和答案
2. 将部分内容写成方法避面主函数过于臃肿。
如main里的输入存储可以单独写成方法。
`String Str = "";
while (sc.hasNextLine()) {
Str = sc.nextLine();
if(Str.equals("end")) {
break;
}
//题目信息的输入
if(Str.contains("#N")){
judgevalid Judge = new judgevalid(Str);
if(Judge.exerciseValid()) {
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);
} else {
System.out.printf("wrong format:%s\n",Str);
}
//试卷信息的输入
} else if (Str.contains(("#T"))) {
judgevalid Judge = new judgevalid(Str);
if(Judge.paperValid()) {
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[i]), Integer.parseInt(parts[i + 1]));
PAPER.getEXES().add(Integer.parseInt(parts[i]));
}
PaperMap.put(Integer.parseInt(parts[1]), PAPER);
if (!PaperSum.contains(Integer.parseInt(parts[1]))) {
PaperSum.add(Integer.parseInt(parts[1]));
}
} else {
System.out.printf("wrong format:%s\n",Str);
}
//答卷信息的输入
} else if(Str.contains("#S")) {
judgevalid Judge = new judgevalid(Str);
if(Judge.answerPaperValid()) {
String[] parts = Str.split("#S:| #A:| |-");
AnswerPaper Anpaper = new AnswerPaper(Integer.parseInt(parts[1]));
Anpaper.setAnswerStuID(Integer.parseInt(parts[2]));
for (int i = 3; i < parts.length - 1; i = i + 2) {
Anpaper.setAnswer(Integer.parseInt(parts[i]),parts[i + 1]);
Anpaper.AnswerOrderAdd(Integer.parseInt(parts[i]));
}
answerPaper.add(Anpaper);
} else {
System.out.printf("wrong format:%s\n",Str);
}
//学生信息的输入
} else if (Str.contains("#X")) {
judgevalid Judge = new judgevalid(Str);
if(Judge.studentValid()) {
String[] parts = Str.split("#X:| |-");
for(int i = 1;i < parts.length - 1;i = i + 2) {
student newStudnt = new student(Integer.parseInt(parts[i]),parts[i + 1]);
studentList.add(newStudnt);
}
} else {
System.out.printf("wrong format:%s\n",Str);
}
//删除题目信息的输入
} else if (Str.contains("#D")) {
judgevalid Judge = new judgevalid(Str);
if(Judge.delExeValid()) {
//String[]
String[] parts = Str.split("-");
exerciseBeDeleted delexe = new exerciseBeDeleted(Integer.parseInt(parts[1]));
delEXE.add(delexe);
}
}
}`
3. 保证完成题目要求的同时避免重复代码。
如输出时为了保证输出次序而使用了重复代码
for(int j = 0; j < PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().size(); j ++) { //j小于对应答卷的题目数时 if (answerPaper.get(i).getAnswers().size() < j + 1) { System.out.println("answer is null"); } else if (!exerciseMap.containsKey(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j))) { System.out.printf("non-existent question~0\n"); } else if (ExeBeDel(exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getNO())) { //System.out.printf("the question %d invalid~0\n",exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getNO()); } else { String exeToprint = exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getContent(); String answerToprint = answerPaper.get(i).getAnswers().get(answerPaper.get(i).getAnswerOrder().get(j)); boolean judgeToprint = exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).judge(answerPaper.get(i).getAnswers().get(answerPaper.get(i).getAnswerOrder().get(j))); System.out.printf("%s~%s~%s\n",exeToprint,answerToprint,judgeToprint); } } for(int j = 0; j < PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().size(); j ++) { if (answerPaper.get(i).getAnswers().size() < j + 1) { //System.out.println("answer is null"); } else if (!exerciseMap.containsKey(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j))) { //System.out.printf("non-existent question~0\n"); } else if (ExeBeDel(exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getNO())) { System.out.printf("the question %d invalid~0\n",exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getNO()); } }