Blog-2 题目集4~6的总结
22207203-陈思思
一、 前言
(一) 第4次题目集(答题判题程序4)
- 知识点主要是类与对象、继承与多态、集合、正则表达式、业务逻辑的处理和设计模式的初步应用等。定义了多个类,每个类都进行了封装。集合方面,使用了 Map来存储问题、考试卷和学生信息,通过键值对快速访问;使用 Set 来存储答案,避免重复答案的判断;使用 List 来存储答卷和输出结果,动态管理数据的大小。本题目要求了一定的设计模式思想,例如策略模式(针对不同的题型采用不同的评分策略)和命令模式(通过输入字符串的不同前缀分发到对应的处理方法)。
- 题量很大。作为最后一次的题目,对于输入输出和内部逻辑的要求的提高了很多。定义了多种题目类型包括单选题、多选题和填空题,还会进行不同题目类型的组合。输入要求支撑多种格式的输入,涵盖了题目、学生、考试卷和答案等多个方面,在功能实现上需要全面考虑一步步改进。最后,每种题目类型的评分逻辑都不一样,实现起来更加复杂。
- 难度大。对于代码的逻辑和架构的要求很高,还需要另外考虑多种异常处理的情况。比如各类题目的评分逻辑较为复杂,需要处理多种情况(如部分正确、完全正确和错误),这种复杂性使得代码在逻辑上需更高的思维能力。考试卷和答卷的管理也相对复杂,涉及到多个类之间的协作,要求对类的设计和结构有清晰的理解。整个系统需要良好的架构设计,以便将不同类型的问题、学生信息和考试处理逻辑清晰地分开,并且能够高效地进行数据管理与操作。除了实现功能,还需考虑到如何处理异常情况(如格式错误的输入、学生或试卷不存在等),这增加了设计的难度。
(二) 第5次题目集(家居强电电路模拟程序1)
- 知识点主要是继承、读取和区分输入类型、处理连接。继承关系定义了一个基类 Electric 和多个子类。基类 Electric:这是所有电器类型的父类,包含了共有的属性和方法。子类:开关类、分档类、连续开挂类、白炽灯类、日光灯类、吊扇类。通过判断连接指令和设备控制指令判断输入烈性,然后进一步解析连接指令和电器对象来处理连接。
- 题量相对较少,包含大部分的底层逻辑,需要慢慢的一步一步搭建好。主要包含以下三点:输入处理、电器连接与状态管理、输出。
输入处理:需要处理多种格式的输入,做出不同的反应。
电器连接与状态管理:需要关联多个电器对象,并根据指令更新它们的状态。
输出:根据电器的状态生成特定格式的输出。
3.难度中等偏上,涉及较多的编程概念,包括面向对象编程、集合的使用、正则表达式、以及对输入输出的处理等。逻辑比较复杂,需要根据不同的输入格式和内容采取不同的操作,同时要理清逻辑关系和各部分之间的相互作用。对于程序设计方面有要求,但是题目给了建议类图适当降低了难度,需要合理设计类的结构和方法,以确保代码可读性和维护性。
(三) 第6次题目集(家居强电电路模拟程序2)
1.在家居强电电路模拟程序1的基础上增加了电器类型落地扇和并联电路,使得整个代码的逻辑实现和架构要求都变得更高了。知识点和第5次题目集相似。
2.题量中等,对于连接处理的逻辑要求更高更复杂了,同时对于输入除了区分电器类型,还要区分电路类型和连接类型。
3.难度偏高,需要对多种输入进行分类处理和存储,输出要求也较高需要按照一定的逻辑进行输出。对于输入电器的连接我个人认为难度是最大的。
二、设计与分析
(一) 第4次题目集(答题判题程序4)
- 类图(太大,分左右两边截)
左边:
右边:
继承关系:通过抽象类 Question 和其子类,提供了一个可扩展的题目结构,允许不同类型的题目在同一框架下运作。
组合关系:主要对象通过组合关系协作,ExamPaper 包含 Question,AnswerSheet 包含 Student 和 ExamPaper,形成一个完整的考试管理系统。
此外还有输入和输出处理类。
1.SourceMonitor报表
分支语句占比为11.1%,
平均圈复杂度为1.05,
平均块深度为1.89,
平均复杂度较低,但最大复杂度较高,说明存在一些较为复杂的方法。总体来看,这个Java文件的代码质量较好,具有合理的复杂度和良好的结构。然而,注释较少,后期应该增加更多的注释,并关注那些复杂度较高的方法,以进一步提高代码的质量。
(二)第5次题目集
1.类图
主要定义了一个基类 Electric 和多个子类。
基类 Electric:是所有电器类型的父类,包含了共有的属性和方法。
Switch(开关):继承自 Electric,实现了开关特有的功能,包括开关的显示与状态切换。
FenDangSwitch (分档):实现电动设备的分档调节,包括速度调节的实现。
LianXuSwitch (连续):实现连续电压的调节。
Lamp(白炽灯):实现电压对输出亮度的影响。
Daylight(日光灯):实现根据电压决定亮度的功能。
Diaoshan (吊扇):根据电压范围调整风速。
通过这种继承关系,可以在子类中复用基类的代码,避免重复,且便于扩展和维护
2.Source Monitor报表
代码长度:总共有469行代码,其中包含306条语句,这表明代码有一定的规模。
分支语句比例:27.5%的语句是分支语句,这是一个合理的比例,表明代码有足够的条件逻辑处理。
方法调用:平均每行代码中有大约0.23次方法调用,这表明代码复用程度适中。
注释覆盖率:只有4.9%的行是注释,这可能是一个潜在的问题点,因为适当的注释有助于理解代码的功能和意图。
复杂度:复杂度比较高尤其是主函数中,后期应该进行功能分割和简化。
块深度:最大块深度为7,平均块深度为2.83,这表明代码层次结构合理,但仍然需要注意避免过深的嵌套。
(三)第6次题目集
1.类图
在第1次的基础上增加了落地扇类和串联类、并联类。
构成了更加复杂的关系。
2.Source Monitor报表
在上次的代码的基础上进行了主类功能的拆分,添加了一些功能模块类。
代码规模:文件包含907行代码,其中有625条语句,代码规模较大。
分支语句比例:占所有语句的27.8%,代码中包含了一定数量的条件判断和流程控制。
方法调用:语句占比较高,共340条,代码中有很多功能模块化的实现。
注释覆盖率:占总行数的5.6%,说明代码中的注释较少,可能影响代码的可读性和维护性。
类和方法:共有16个类和接口,平均每个类有2.44个方法,类的设计较为简洁。
平均每个方法有15.38条语句,方法的大小适中。
复杂度:最复杂的方法是Calculate_shuV.calculate_shuV(),复杂度为28,位于第276行。
最深层次的块位于第304行,深度为8。
平均复杂度为5.57,说明整体代码的复杂度处于一个可控范围内。
块深度分布:块直方图显示大部分块的深度分布在1到5之间,深度较大的块数量较少,代码的层次结构较为清晰。
三、 踩坑心得
(一) 第4次题目集
1.输出的排序问题
题目要求多个同学多张试卷的情况下,输出顺序优先级为学号、试卷号,按从小到大的顺序先按学号排序,再按试卷号。
未进行排序前,我的代码会按照输入的信息顺序对学生的答卷信息进行输出,后面经过一系列的搜索与学习,使用了一个简单的语句进行排序,如下。
2.解决方法
// 按学号和试卷号排序 answerSheets.sort(Comparator.comparing(AnswerSheet::getStudentId) .thenComparing(AnswerSheet::getExamPaperId));
方法解释:
answerSheets.sort(...):这是对 answerSheets 列表调用排序方法。answerSheets 是一个 List
Comparator.comparing(...):这是一个静态方法,用于创建一个比较器(Comparator)。它接收一个提取器方法(该方法用于提取用于比较的键)作为参数,这里提取的是每个 AnswerSheet 对象的学生ID (AnswerSheet::getStudentId)。
thenComparing(...):在第一个比较器的结果相等时,使用 thenComparing() 进行第二个级别的比较。这里是按试卷ID进行排序 (AnswerSheet::getExamPaperId)。
3.结果对比
使用前,测试输出:
使用后,测试输出:
(二)第5次题目集
1.问题
这次的题目,难倒我的主要是怎样将输入的器件连接起来,形成串联电路。
2.心得与方法
(1) 输入处理
在 main 方法中,使用 Scanner 对象读取用户输入。输入通常包括两个主要部分:设备连接信息和指令(如开关状态或控制命令)。
1.读取设备连接:
如果输入以 [ 开始,这表示一个连接指令,程序会提取并格式化内容添加到 connection 列表中。
例如,输入 [ VCC K1 GND D1 ] 将被解析并存储。
2.读取控制指令:
如果输入以 #K, #F, #L 等开头,这些被视为控制指令。相应的参数将被解析并添加到 chw 列表中。
(2) 连接设备
在 connection 列表中存储了所有的设备连接信息,下面的逻辑负责解析这些连接并创建相应的电器对象:
for(mmm = 0; mmm < connection.size(); mmm++){
z1 = connection.get(mmm);
String[] parts4 = z1.split(" ");
String []plants = new String[parts4.length];
for(i = 0; i < parts4.length; i++){
plants[i] = parts4[i];
}
kllk = i - 1; // kllk存储最后一个元素的下标
if(plants[0].equals("VCC")){
// 处理VCC连接
for(i = 1; i < plants.length; i++){
String[] pinyin = plants[i].split("-");
String dkey = pinyin[0].trim();
if(pinyin[pinyin.length - 1] == null) continue;
else{
if(pinyin[pinyin.length - 1].equals("1")){
map1 = complain(dkey, plants[i], map1);
}
}
}
}
...
}
连接处理逻辑
1.检测连接类型:
检查设备连接的起始部分(如 VCC, GND 等),这些关键词帮助确定电源类型。此处的示例是,当发现 VCC 时,从第二个元素开始处理作为电子设备的连接。
2.调用 complain 方法:
对于每个连接的设备,通过 complain 方法处理,#### 添加到 map1 中。
在这个方法中,会根据设备类型(开关、分档、连续、白炽灯、日光灯、吊扇)创建相应的对象并将其存储在 map1 中。
public static Map<String, Electric> complain(String dkey, String s, Map<String, Electric> map1){
String jkj = String.valueOf(s.charAt(1));
if (s.startsWith("K")) {
Electric tric = new Kaiguan(jkj);
map1.put(dkey, tric);
}
...
return map1;
}
(3) 控制命令
在 chw 列表的控制指令部分,针对不同的指令(#K, #F, #L)执行相应的操作,如开关、调节等。
for (i = 0; i < chw.size(); i++) {
String sid = chw.get(i);
if (sid.startsWith("K")) {
String diu = sid.substring(0, 2);
Electric electric = map1.get(diu);
...
} else if (sid.startsWith("F")) {
...
} else if (sid.startsWith("L")) {
...
}
}
控制逻辑的处理:
每种控制指令会对应到 map1 中的一个设备对象,程序根据指令的类型执行对应的操作,如调节速度、改变开关状态等。
例如,当接收到指令 #K 时,程序会查找对应的开关,判断其状态,如果是开启状态则关闭;如果是关闭状态则开启。
(4) 显示输出
在最后,所有的设备状态会通过 display 方法输出到控制台,设备信息会以预定的格式显示。
for (Electric suixcs : arraylist6) {
suixcs.display();
}
3.结果
掌握前:
掌握后:
(三)第6次题目集
1.问题
怎样将串联电路与并联电路划分开来。
2.心得与方法
在我的 InputElectric 类中,opration 方法将根据输入的不同类型(以不同的前缀字符开头)将设备的连接方式分辨出来:串联电路以 #T 开头;并联电路以 #M 开头。
如果是串联电路会提取出型号并将其添加到 connection 列表中,表明这是一个串联连接。如果是并联电路,将相关信息存储在 connection1 列表中。
在 main 方法中,还会使用额外的逻辑来把串联和并联电路分别存储:
for (int mmm = 0; mmm < connection.size(); mmm++) {
// 串联电路存储逻辑
...
if (vb1 == 1) {
mac.put(zm, map1); // 并联电路
}
if (vb2 == 1) {
zhu = map1; // 主电路
}
}
这种标签化的方式,有助于在后续的电路计算和电压更新中轻松区分并联和串联电路。
3.结果
详细化之前:
详细化之后:
四、 改进建议
在题目集4中,有很多异常处理,我是用的是在相应的类中自行处理,之后可以引入自定义异常类来处理不同类型的错误。例如:InputFormatException:处理输入格式错误的情况。QuestionNotFoundException:处理试卷中引用了不存在题号的情况。StudentNotFoundException:处理学生信息中不存在的学号。在处理题型的整理时,有些逻辑是重复的。之后改进可以将重复的逻辑提取成辅助方法或函数。例如,处理输入的逻辑可以整合到一个方法中,通过参数区分不同的处理方式,减少代码的冗余。当前支持的题型是选择题、填空题、多选题,可以考虑实现其他题型,如:简答题、排序题等。
题目集5和6中,一些类(如 Electric 类)包含多个职能,可能会造成类的职责不明确,之后会考虑改进将设备的每个功能(如状态管理、电压调整)进一步抽象为小的类。可以创建接口或抽象类,以提供设备状态和行为的一致框架。当前题目只支持开关、调速器、灯具和风扇。如果需要增加新设备,需大幅修改现有代码。之后会使用工厂模式来创建电器对象,以便能够轻松添加新的电器类型而不需更改现有代码结构。
五、总结
在本次实验中,我们完成了三个题目集的任务,分别是答题判题程序、家居强电电路模拟程序1和家居强电电路模拟程序2。这些任务涵盖了类与对象、继承与多态、集合、正则表达式、业务逻辑处理和设计模式的应用。
首先,在答题判题程序中,我们定义了多个类来封装不同类型的题目,如单选题、多选题和填空题。通过使用Map、Set和List等集合类,实现了对题目、考试卷和学生信息的高效管理。策略模式和命令模式的应用使评分逻辑和输入处理更加灵活。不过,代码中存在一些复杂方法和较低的注释覆盖率,需要增加注释并优化这些方法。
其次,在家居强电电路模拟程序1中,我们设计了一个基类Electric和多个子类,如开关、分档、连续、白炽灯、日光灯和吊扇。通过继承关系,复用了基类的代码,避免了重复。输入处理方面,通过正则表达式和字符串解析技术,成功处理了多种格式的输入,并实现了设备的连接和状态管理。尽管如此,主函数的复杂度较高,需要进行功能拆分,降低复杂度。
最后,在家居强电电路模拟程序2中,我们在原有基础上增加了落地扇类和并联电路的支持,使系统的逻辑更加复杂。通过引入不同的前缀字符和标签化的方式,区分了串联和并联电路,简化了电路管理。尽管如此,代码中仍存在重复的逻辑和复杂的控制结构,计划引入工厂模式来创建电器对象,并进一步抽象设备功能。
在整个实验过程中,我深刻体会到设计模式的重要性。合理运用设计模式可以提高代码的灵活性和可扩展性,降低系统复杂度。此外,异常处理也不可忽视。在答题判题程序中,通过自定义异常类处理各种错误情况,提高了系统的健壮性和错误处理的清晰度。
总之,通过这次实验,我在面向对象编程和设计模式方面有了更深的理解和实践。未来,我将继续优化代码结构,提高代码的可读性和可维护性,争取在实际项目中应用所学知识,解决更复杂的问题。