前言
(1) 第四次题集的第一题已经经过了三次迭代,需要考虑到的情况越来越复杂,难度也越来越大,这让我感受到面向对象编程的基本原则的重要性,此前每一次迭代都应该谨慎,切忌为了偷懒就破坏类之间的关系(我第二次迭代就偷懒过了所有测试点,然后最后一次就狂改)。
(2) 第五次题集只有三道题,也是第一次迭代难度不大,但是进过前面几次大作业的磨练,我对类的使用明显愈发熟练,本次大作业用到了抽象类,我将电路设备定义为了抽象类,很轻松的AC这道题。
然后是这题集的第三题,首次接触了集合类型,这道题是改错题,声明类型是Collection,实际类型是ArrayList,然后使用迭代器遍历所以员工,难度一般。
(3) 第六次题集只有一道题(看起来挺唬人),难度也没有很大,经过第一次迭代,加入了并联电路,电路设备也变多了,但是有一个关于精度的计算很难考虑到,花了很长时间调试。
第四次题集
设计与分析:
本次题集除了第三题其他都是很基础的题目,就分析一下最后一题,以下是类图:
本次大作业我设计的主要的几个类分别是
(1) 题目类(Question):用于保存一道题目的信息以及处理的方法。(与系列 1 相同,无变化)
private int num;// 题号
private String content, // 题目内容
standardAnswer;// 标准答案
boolean matchingStandardAnswers(String answer):判断是否符合标准答案
boolean isValid=true;//是否是有效的题目
void disabled() //当题目被删除,设置题目为失效状态
ArrayList
(2)试卷题目类(Question_Paper):用于保存试卷中的题目信息。由于试卷中的题目序号与题
目本身的题号不一致。且题目在不同试卷中的分值可能不一样,因此,设计试卷题目类。
int p_q_num;//试卷中题目的顺序号
Question question;//题目类的对象,保存题目信息
int question_score;// 题目分值
int judge_markAnswer(String answer) // 判断题目得分
(3)试卷类(TestPaper):保存和处理一张试卷的信息以及处理的方法,
int questionNum;// 题目数量
HashMap<String, Question_Paper> questions;//题目清单
void inputQuestion(int num, Question question):添加一道题目
void printQuestions():输出题目的内容~标准答案
boolean markQuestion(int num, String answer):判断第 num 题的正确性。
int sum-保存总分
int questionQuantity-保存题目数量
int getSum()****:获得总分
(4)答案类(Answer):用于保存答卷中一道答案的信息。
Question_Paper question;
String answer;
boolean mark;// 每一题的正确性
int score=0;// 每一题的得分
void calScore()//计算得分
void disable() //答案对应的题目失效,判分为 0
(5)答卷类(AnswerPaper):保存和处理一张答卷的信息以及处理的方法
TestPaper paper;//试卷信息
String[] answers;//每一题的答案信息boolean[] marks;//每一题的判题结果(对/错)
void printQ_A(int num):输出第 num 题的题目和答案(卷面答案,非标准答案)
boolean getJudge(int num):获得第 num 题的判题结果
void printJudges() :// 输出所有的得分以及总分,以空格分隔
String stuNum;// 学号
void** printErrorNumQuestion(Answer answer) // 输出试卷中错误题目号的题目
void** printInvalidQuestion(Answer answer)// 输出失效题目信息
(5)学生类(Student):保存学生的信息
String stuNum, stuName;
踩坑心得:
(1) 首先这次的大作业,我最后还有一个测试点没有过,现在我弄明白了,但是时间已经过了,这个题目的空白卷输入,就是只有一个卷子,没有题目序号,应该按正常的卷子输出,我的正则表达式有问题,没有捕捉到这种情况。
例如:
输入:#N:1 #Q:1+1= #A:2
T:1 1-5
X:20201103 Tom
S:1 20201103 #A:
end
应该将这种情况正常输出。
(2) 我这次又犯了上次同一个错误,正则表达式写错了,导致捕捉不准确。
public static boolean checkquestion(String str){String regstr="^#N:\\d*\\s*#Q:.*#A:.*";Pattern pattern= Pattern.compile(regstr);Matcher matcher=pattern.matcher(str);if(matcher.find()){return true;}else{return false;}}public static boolean checktest(String str){String regstr1="(\\d*)-(\\d*)";Pattern pattern1=Pattern.compile(regstr1);Matcher matcher1=pattern1.matcher(str);String regstr2="^#T:\\s*\\d+\\s*((\\d+\\s*-\\s*\\d+\\s*)+)$";Pattern pattern2=Pattern.compile(regstr2);Matcher matcher2=pattern2.matcher(str);if(matcher2.find()){return true;}else{return false;}}public static boolean checkstudent(String str){String regstr2="^#X:\\s*\\d+\\s(.*?)+(?:-\\d+\\s(.*?)+)*$";Pattern pattern1=Pattern.compile(regstr2);Matcher matcher1=pattern1.matcher(str);if(matcher1.find()){return true;}else{return false;}}
这几个check方法最后在同学的帮助下终于是改对了,下一次一定要仔细读取题目意思,谨慎考虑好之后在开始,不然写到一半出了问题很崩溃的。
改进建议:
这次写的大作业,还是出现前三次的问题,就是类之间的关系有些模糊不清,写到后面经常性用错,但是比起前几次的乱七八糟的代码,至少类的功能分的清楚了。
(1) 这次大作业如果将同学与答卷号码用HashMap保存起来,后续只需要通过迭代器就可以遍历所以答卷和学生,不用再像现在这样遍历所以答卷找同学,可以增强代码的可读性,而且代码也会更简洁,维护起来也容易。
(2) 试卷题目类也可以使用List泛型代替ArraysList存储试卷与题目的关系,这样可以直接使用Collections.sort方法进行排序。
第五次题集:
设计与分析:
首先是这次题集的第一题,这是第一次出现,还没有进行迭代,特殊条件比较多难度一般,以下是类图:
这里主要设计了两个类:
(1) 电路设备类(Equipment):描述所有电路设备的公共特征。
abstract class Equipment {int switchstyle;//如果是开关 开关的状态public int getSwitchstyle() {return switchstyle;}public boolean IfPathway(){return false;}double voltage;//设备分到的电压public double getVoltage() {return voltage;}abstract public void setVoltage(double c);double resistor;//电阻abstract double getResistor();public double getContact1() {return contact1;}public void setContact1(double contact1) {this.contact1 = contact1;}String name;//设备名public String getName() {return name;}double contact1;//触脚1的电压public double getContact2() {return contact2;}public void setContact2(double contact2) {this.contact2 = contact2;}double contact2;//触脚2的电压abstract void display();//输出设备的状态abstract void close();}
(2) 串联电路类(Series):一条由多个电路设备构成的串联电路,也看成是一个独立的电路设备。以下是部分代码:
class Series {public double getVoltage() {return voltage;}public void setVoltage(double voltage) {this.voltage = voltage;}private double voltage;public String getName() {return name;}public void setName(String name) {this.name = name;}private String name;public void VoltageDivision(){double aver=getVoltage()/getResistor();for(int i=0;i<list.size();i++){Equipment e= list.get(i);if(e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor)continue;else{e.setVoltage(aver*e.getResistor());}}}private double resistor;public double getResistor() {resistor = 0;for (int i = 0; i < list.size(); i++) {Equipment e = list.get(i);if (e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor)continue;elseresistor += e.getResistor();}return resistor;}
}
将设备类定义为抽象类,其余所有电器继承与设备类,然后使用串联电路类,然后将每个电路元件存入其中,
判断控制电器的状态,判断电路是否通路,模拟各种情况,最后输出各个元件的状态。
其中串联电路类内部使用ArrayList类型保存每一个设备,最后确定没一个开关的状态,最后进行排序输出即可。
然后是这次题集的第三道题,首次接触到了集合类型,这道题是一道改错题,使用Collection
保存每一个员工,使用迭代器遍历输出,难度也一般。
//主函数
public class Main {public static void main(String[] args) {// 1、创建有序集合对象Collection <Employee>c = new ArrayList();Scanner sc = new Scanner(System.in);// 创建3个员工元素对象for (int i = 0; i < 3; i++) {String employeeName = sc.nextLine();int employeeAge = sc.nextInt();sc.nextLine();Employee employee = new Employee(employeeName, employeeAge);c.add(employee);}// 2、创建迭代器遍历集合Iterator <Employee>it=c.iterator();//3、遍历while (it.hasNext()) {//4、集合中对象未知,向下转型Employee e = (Employee) it.next();System.out.println(e.getName() + "---" + e.getAge());}}
这是Main方法部分,声明了一个迭代器it,接收集合c的迭代器,然后遍历。
踩坑心得:
(1) 这次的大作业难度不大,但是由于看漏了条件,导致最后有几个测试点一直没有通过,这道题允许开关多次出现,最后输出结果要排序。后来我就声明了一个ArrayList类型专门保存所有开关,只有一遇见开关,就将这开关对象存入,判断是否有开关存在,如果有就排序输出。同时开关类也实现了Comparable接口。
@Overridepublic int compareTo(Switch o) {if (name.compareTo(o.getName()) < 0)return -1;elsereturn 1;}
(2) 还有本次大作业的分档变速器是必须在0-3之间,不能炒出这个范围的,需要加上特判条件。
例如:
else if(Line.contains("#F")){if(Line.contains("+")&&gears<3){gears++;}else if(Line.contains("-")&&gears>0){gears--;}}
这样保证档位不会超出范围。
改进建议:
(1) 下一次迭代肯会将入并联电路,所以应将串联电路继承于电器设备类,这样方便下次迭代。
(2) 对于其他电路设备可以像对待开关一样操作,这次大作业说明了其余设备只出现一次,但是下次不一定,所以全部使用List泛型存储,在实现Comparable接口,方便排序。
以吊扇类为例:
@Overridepublic int compareTo(Fan o) {if(name.compareTo(o.getName())<0)return -1;elsereturn 1;}if(D.size()!=0){Collections.sort(D);for(int i=0;i< D.size();i++)D.get(i).display();}
这样所有电路设备多次出现排序的问题就可以解决。
第六次题集:
设计与分析:
这次大作业比起上次大作业多了一个并联电路,将并联电路视为一种特殊的电路元件即可,但同时也需要主要并联电路的电阻和电压的计算涉及到精度问他。以下是新的类图:
这次主要的增加的新类:
(1) 并联电路类(Parallel):继承电路设备类,也看成是一个独立的类。
以下是主要属性和方法:
class Parallel extends Equipment {private ArrayList<Series> seriesList;Parallel(ArrayList<Series> seriesList) {this.seriesList = new ArrayList<>();this.seriesList = seriesList;}@Overridepublic void setVoltage(double c) {for(int i=0;i<seriesList.size();i++){Series series=seriesList.get(i);if(series.IfPathway()){series.setVoltage(c);series.VoltageDivision();}}}@Overridepublic boolean IfPathway()//检查并联是否通路{for(int i=0;i<seriesList.size();i++){if(seriesList.get(i).IfPathway()){return true;}}return false;}@Overridedouble getResistor() {for(int i=0;i<seriesList.size();i++){if(seriesList.get(i).Ifshort()){return 0;}}double r = 0;double R = 0;for (int i = 0; i < seriesList.size(); i++) {Series s = seriesList.get(i);if(s.IfPathway()){R += (1.0 / s.getResistor());}}r = (1.0 / R);return r;}@Overridevoid display() {}@Overridevoid close() {}
}
并联电路也是一个特殊的电路设备,所以他也有名字,电阻,电压。需要注意的是并联的电阻计算和电压的计算会有精度问题。
题干中说明了并联电路所包含的串联电路会在其之前输入,所以只要将每一条路(出了连接电源的串联)存在一起,创建并联电路时一起加入就行。
踩坑心得:
(1 )这道题涉及到并联电路电阻的计算,那么就肯定会出现一些,无限循环小数等非常规小数,导致计算结果出错。
例如:
输入:
#T1:[IN K1-1] [K1-2 D2-1] [D2-2 D3-1] [D3-2 OUT]
#T2:[IN K2-1] [K2-2 D1-1] [D1-2 OUT]
#M1:[T1 T2]
#T3:[VCC L1-1] [L1-2 M1-IN] [M1-OUT GND]
#K1
#K2
#L1:1.00
end
错误输出:
@K1:closed
@K2:closed
@L1:1.00
@D1:360
@D2:199
@D3:199
这是一个人标准错误的答案。
正确输出:
@K1:closed
@K2:closed
@L1:1.00
@D1:360
@D2:200
@D3:200
当D2的转速为199.99999时最后应输出200,而不是199。这是计算电压是,没有处理好。需要进行精度判断,如:
double TF=c1-Math.floor(c1);double TC=Math.ceil(c1)-c1;if(Math.min(TF,TC)<1e-10){c1=Math.round(c1);}
这需要每次计算电压时加上这个判断即可AC。
改进建议:
下次迭代是可能会加入并联电路串联的情况,所以在加入并联电路时需要进行遍历所有此前的串联,找到符合的串联,再加入并联电路中。为了应对各种迭代情况,所以类之间的耦合性一定要设法降低,不能导致牵一发而动全身,这样修改代码的工作量太大了。
总结:
对面向对象编程(OOP)概念理解加深了,Java是一种面向对象的语言,通过这三次作业,更深入地理解类、对象等概念。
然后代码组织与结构的能力增强,编写大型Java程序需要良好的代码组织和结构。
逐渐熟练如何使用接口、类组织代码,以及如何使用注释来提高代码的可读性。
调试能力提高,调试是开发过程中不可或缺的一部分。学会如何使用调试工具和技巧来定位和修复代码中的错误。
还精通了许多类的使用例如LinkList,ArraysList,HashMap等等。
然后是一些建议:
对于模拟家用电器控制系统可以在并联电路中加入一些特殊的元件,如电阻器,变压器等等,这样更符合实际情况。
之后的PTA作用可以加入一些算法数据结构的知识,促进我们自学,这几次作用都没有什么算法知识。
可以加入更多关联实际的题目,增强对面向对象的理解。