题目集4~6的总结性Blog
题目集4~6的总结性Blog🤗

(目录可以点击侧边提示使用哦😊😊😊)
目录
1. 前言
1.1答题判题程序-4知识点、题量、难度分析
1.2家居强电电路模拟程序-5知识点、题量、难度分析
1.3家居强电电路模拟程序-6知识点、题量、难度分析
2. 设计与分析
2.1答题判题程序-4设计与分析
2.2家居强电电路模拟程序-5设计与分析
2.3家居强电电路模拟程序-6设计与分析
3. 采坑心得
3.1答题判题程序-4采坑心得
3.2家居强电电路模拟程序-5采坑心得
3.3家居强电电路模拟程序-6采坑心得
4. 改进建议
4.1答题判题程序-4改进建议
4.2家居强电电路模拟程序-5改进建议
4.3家居强电电路模拟程序-6改进建议
5. 总结
5.1本阶段三次题目集收获
5.2深入学习探究的思考
5.3问题改进与建议
1. 前言
为突出本次题目集的侧重点,在题目集1~3的总结中涉及到的相同代码段的重复知识点不再本次题目集总结中赘述🙊
1.1答题判题程序-1知识点、题量、难度分析

一、继承关系
1.MultipleChoiceQuestion和FillInTheBlankQuestion类继承自Question类,通过extends关键字实现继承关系。
子类继承了父类的属性(如number、content、standardAnswer)和方法(如构造函数等)。
class MultipleChoiceQuestion extends Question
class FillInTheBlankQuestion extends Question
2.子类对象在创建时会调用父类的构造函数来设置共有的属性
子类调用父类构造函数:
super(number, content, standardAnswer);这行代码调用了父类Question的构造函数,并传递了相同的参数,以此确保MultipleChoiceQuestion对象在创建时,其基本属性(编号、内容、标准答案)都被正确设置。这些属性是从父类Question继承而来的。
点击查看代码
public MultipleChoiceQuestion(int number, String content, String standardAnswer) {
super(number, content, standardAnswer);
}
3.方法重写与覆盖
父类题目答案正确性检测checkAnswer方法在子类中被重写,以适应特定类型填空题、多选题的答案检查逻辑。
点击查看代码
class Question {
public boolean checkAnswer(String answer) {//父类方法
//...
}
}
class MultipleChoiceQuestion extends Question {
@Override //子类重写父类方法标志
public boolean checkAnswer(String answer) {//...}
}
👣重写相关知识点:(干货集合!!!)
- 代码重用:继承允许子类重用父类的代码,这减少了重复代码的编写,提高了开发效率。
- 层次结构:继承可以创建一个层次结构,其中子类是父类的特化。这种结构有助于组织和管理代码。
- 方法重写:子类可以重写(Override)父类的方法,以提供特定于子类的行为。
- 属性继承:子类继承父类的属性(字段),但可以添加新的属性或修改继承的属性。
- 构造函数:子类可以调用父类的构造函数来初始化继承的属性,使用super()关键字。
- 访问控制:子类可以访问父类的公共(public)和受保护(protected)属性和方法,但不能访问私有(private)属性和方法。
- 多态性:继承是实现多态性的基础,允许子类对象被当作父类对象使用,从而在运行时根据对象的实际类型调用相应的方法。
- 方法隐藏:如果子类定义了一个与父类同名的方法,这会隐藏父类的方法,而不是重写它。
- final关键字:使用final关键字可以防止类被继承,或者防止方法被重写。
- super关键字:在子类中,super关键字用于访问父类的属性和方法,特别是在子类的构造函数中。
- 继承的传递性:如果类B继承自类A,类C继承自类B,那么类C也间接继承自类A。
- 抽象类:抽象类不能被实例化,它通常包含抽象方法,这些方法在子类中必须被实现。
- 接口:虽然接口不是通过继承实现的,但它允许类实现多个接口,这在某种程度上提供了类似于多重继承的功能。
- 组合与继承:在某些情况下,使用组合(即在类中包含另一个类的实例)而不是继承可能更合适,因为组合提供了更大的灵活性。
- 设计原则:继承应该遵循里氏替换原则(Liskov Substitution Principle),即子类对象应该能够替换掉所有使用父类对象的地方,而不会引起程序错误。
二、多态
在AnswerSheet类的judgeAnswers方法中,通过question.checkAnswer(answerStr)调用Question类及其子类的checkAnswer方法。根据question对象的实际类型(可能是Question、MultipleChoiceQuestion或FillInTheBlankQuestion),会执行相应子类重写后的checkAnswer方法,这体现了多态的特性,即根据对象的实际类型来决定调用哪个具体的方法实现,实现了代码的灵活性和可扩展性。
点击查看代码
// 在AnswerSheet类的judgeAnswers方法中体现多态
public void judgeAnswers() {
Set<Integer> keys = paper.outScore().keySet(); // 获取 score 的键集合,即题号
for (Integer questionNumber : keys) {
//...获取答案等相关操作...
Question question = paper.questions.get(position);}}
- 抽象类和接口:多态通常与抽象类或接口一起使用,它们定义了子类必须实现的方法。
- 方法重写:子类通过重写父类的方法来提供特定的实现,这是实现多态的关键。
- 动态方法调度:Java在运行时会根据对象的实际类型来调用相应的方法,这是多态性的核心。
- 引用变量的类型:在多态中,引用变量的类型可以是父类类型,而实际对象可以是任何子类类型。
- 对象的类型检查:在多态中,可以使用instanceof操作符来检查对象是否是特定子类的实例。
- 方法调用:在多态中,方法调用是通过引用变量的类型来决定的,但是实际执行的代码取决于对象的实际类型。
- 设计模式:多态是许多设计模式的基础,如工厂模式、策略模式等。
三、使用Lambda表达式和自定义比较器来处理和排序数据
按照学生信息的学号顺序和试卷号顺序对答卷输出进行排序时,首先使用增强型for循环遍历students这个HashMap的entrySet,将每个学生的ID添加到studentIds列表中,然后使用Lambda表达式和自定义比较器来处理和排序数据。
- 排序:
java.util.Collections.sort(studentIds);:使用Collections类的sort方法对studentIds列表进行排序。默认情况下,这将按照字母顺序对学生ID进行排序。
java.util.Collections.sort(studentIds); - 自定义排序:
点击查看代码
// 对学生的答卷按照学号和试卷号排序
answerSheetsForStudent.sort((a1, a2) -> {
int compareStudentId = Integer.compare(a1.inputTestNumber, a2.inputTestNumber); // 学号比较
if (compareStudentId!= 0) {
return compareStudentId;
}
return Integer.compare(a1.paper.number, a2.paper.number); // 试卷号比较
});
🐌亲测有效的排序万能结构!!!
- Lambda表达式:
(a1, a2) -> {...}:这是一个Lambda表达式,用于定义排序的比较逻辑。它接受两个AnswerSheet对象作为参数,并返回一个整数,该整数表示两者的排序关系。
方法引用: - Integer.compare(a1.inputTestNumber, a2.inputTestNumber):这是一个方法引用,它调用Integer.compare方法来比较两个整数,并返回比较结果。
- 比较器(Comparator):
整个Lambda表达式作为Comparator接口的实现,用于定义排序逻辑。Comparator是Java中用于定义排序规则的接口。 - 链式比较:
在比较两个对象时,首先比较一个属性,如果相等再比较另一个属性。这种比较方式称为链式比较。 - 事件驱动的排序:
排序操作是在遍历学生信息并收集答卷数据之后进行的,这是一种事件驱动的数据处理方式。
四、静态方法与静态变量
静态方法和静态变量是Java中与类相关联而不是与特定对象实例相关联的成员。它们属于类本身,而不是类的任何对象。AnswerSheet类中的testposition是一个静态方法,它接受一个Map和一个key作为参数,用于查找key在Map中的索引位置。
Main类中的scanner是一个静态变量,它用于从命令行读取输入。
Main类中的testPapers是一个静态变量,它是一个HashMap,用于存储TestPaper对象。
静态方法和静态变量使得代码更加模块化,可以在不创建对象的情况下使用类的功能。
点击查看代码
// 在AnswerSheet 类中使用静态方法
class AnswerSheet {
//...其他属性和方法...
private static int testposition(Map<Integer, Integer> map, Integer key) {
//...
}
// 在主类中使用静态变量
public class Main {
static Scanner scanner = new Scanner(System.in);
static Map<Integer, TestPaper> testPapers = new HashMap<>();
//...
}
- 输入信息种类及可能的数量情况:
- 题目信息:题目明确提到题目信息可多行输入,且题号不一定按顺序,题目的数量理论上可以是任意多个。不同类型的题目都分别按各自格式输入。
- 试卷信息:同样可多行输入,一张试卷对应一行输入信息,试卷的数量也可由用户根据需求自由输入,没有明确的数量限制。
- 学生信息:只输入一行,但这一行中可以包含多个学生的信息,通过 “-” 分隔不同学生的学号和姓名,所以学生的数量同样可多可少。
- 答卷信息:按行输入,每一行为一张答卷的答案,答卷数量取决于参与测试的学生人数以及每个学生完成的试卷数量,没有固定的数量限制。
- 删除题目信息:可多行输入,每条信息对应删除一道题目,其数量取决于需要删除的题目数量,可多可少,也可能没有(即不进行题目删除操作)。
- 输出信息种类及对应数量情况:
- 试卷总分警示:输出与否取决于试卷总分是否等于 100 分,若有多张试卷且总分不等于 100 分的试卷存在,就会按输入顺序输出相应的警示信息,数量最多与试卷数量相同(每张不符合总分 100 分要求的试卷输出一条警示)。
- 答卷信息:根据每张试卷的题目数量以及参与答题的学生人数和答卷数量输出多行数据。对于每张答卷的每道题,都会有一行对应的答题信息输出,所以其数量是参与答题的学生所答试卷的题目总数之和。
- 判分信息:与答卷信息相对应,每一张答卷会输出一行判分信息,包含该答卷对应试卷的每道小题计分及总分。
- 被删除的题目提示信息:若有题目被删除且被试卷引用,在输出答案时会针对被删除题目输出提示信息。
- 题目引用错误、格式错误、试卷号引用错误提示信息。
- 输入解析:程序需要能够解析不同格式的输入信息,这涉及到字符串处理和正则表达式的使用。
- 排序和输出:程序需要按照学号和试卷号对学生的答卷进行排序,并按照指定格式输出答题信息和判分信息。
- 多态和继承:程序中可能需要使用多态和继承来处理不同类型的题目。
- 静态方法和变量:程序中会使用静态方法和变量来处理全局数据。
- 新增内容的复杂性:新增的多选题和填空题的评判逻辑增加了程序的复杂性,需要实现更复杂的答案匹配和分数计算规则。
- 测试和验证:由于程序涉及多种输入和输出格式,以及多种业务逻辑,因此需要进行充分的测试和验证来确保程序的正确性。
1.2答题判题程序-5知识点、题量、难度分析

🐌🐌🐌与先前题目集重复部分的知识点不再赘述
一、通过API使用Math 类的Math.min() 和 Math.max() 方法来控制分档调速器在0-3范围
speedLevel = Math.min(3, speedLevel + 1);
speedLevel = Math.max(0, speedLevel - 1);
条件运算符:
Math.min() 和 Math.max() 是Java中的两个方法,用于获取两个数值中的最小值和最大值。
Math.min(3, speedLevel + 1) 确保 speedLevel 的值不会超过3。
Math.max(0, speedLevel - 1) 确保 speedLevel 的值不会低于0。
这是一种常见的模式,用于控制具有有限状态的变量,例如速度级别、音量级别等,增加了代码的健壮性。
二、在处理不同类型的对象时,instanceof 可以用来确定是否可以安全地将对象引用转换为另一个类型,或者调用某个特定类型的特定方法。
if(device instanceof Switch)
if(connectedDevice instanceof Bulb)
instanceof 是Java中的一个关键字,用于检查一个对象是否是特定类的实例。这个操作符返回一个布尔值(true 或 false),表示左边的对象是否是右边类(或接口)的实例。
instanceof 的基本语法是 object instanceof class,其中 object 是要检查的对象,class 是要检查的类。instanceof 操作符的结果取决于对象的实际类型,这意味着它在运行时检查类型,而不是在编译时。
但是要注意,在泛型代码中,instanceof 操作符不能用于泛型类型参数的直接检查,因为泛型信息在运行时会被擦除(类型擦除)。
三、定义的列表可以存储 Device 类型及其任何子类型的对象时,需要显式类型转换,告诉编译器列中某一项实际上是一个子类对象,因为需要访问该子类特有的方法和属性,而这些在主类中可能不可用。
List<Device> connectedDevices = new ArrayList<>();//设备类
Fan fan = (Fan) connectedDevice;//子类吊扇类
Fan fan = (Fan) connectedDevice; 这行代码是一个显式类型转换,它告诉编译器你确信 connectedDevice 实际上是一个 Fan 对象。这种转换是必要的,因为 connectedDevices 列表被声明为存储 Device 类型的对象,即使列表中的对象可能是 Fan 类型的。Fan 类可能有一些 Device 类没有的方法和属性。如果你需要访问这些 Fan 特有的方法和属性,就必须先将 Device 类型的对象转换为 Fan 类型。
四、字符串处理
1.String类中的substring方法用于提取字符串的一部分,并返回一个新的字符串。
这个方法可以接受一个或两个参数:
当只有一个参数时,它接受一个整数beginIndex,表示子字符串的起始位置(从0开始计数)。
String action = command.substring(3);
command.substring(3)使用了单个参数的substring方法,表示从command字符串的索引3(即第四个字符,因为索引从0开始)开始提取子字符串,直到字符串的末尾。
当有两个参数时,它接受两个整数beginIndex和endIndex,表示子字符串的起始和结束位置。
String type = command.substring(1, 2);
command.substring(1, 2)表示从command字符串的索引1(即第二个字符,因为索引从0开始计数)开始提取,直到索引2(即第三个字符)之前结束。例如在处理连续调速器#L1:0.68输入格式的时候,提取到了L设备类型字符。
2.在处理连续调速器#L1:0.68输入格式的时候,使用String类中的replaceAll方法替换字符串中所有匹配正则表达式的部分,使其能够分离出所需的double类数值0.68
String num1 = action.replaceAll("[^\\d.]+", "");
action.replaceAll("[^\d.]+", "")的意思是:在action字符串中查找所有非数字和非点号的字符,并将它们替换为空字符串(即删除这些字符),使其能够分离出所需的double类数值。
- 控制设备模拟:包括开关、分档调速器、连续调速器的模拟。
- 受控设备模拟:包括灯(白炽灯和日光灯)和风扇(吊扇)的模拟。
- 设备信息输入:解析设备标识和引脚格式。
- 连接信息处理:处理设备引脚之间的连接。
- 控制设备调节信息处理:根据输入调节控制设备的状态。
- 电源接地标识处理:处理VCC和GND的电压。
- 输出信息生成:根据设备状态生成输出信息。
- 电路原理理解:需要对电路的基本原理有深入的理解,特别是串联电路和电压、电流的关系。
- 系统设计能力:需要设计一个能够模拟电路行为的系统,包括设备类的设计、电路连接的处理、设备状态的更新等。
- 输入输出处理:需要解析复杂的输入信息,并根据这些信息更新系统状态,最后生成符合要求的输出信息。
- 异常和边界情况处理:需要考虑各种异常情况和边界条件,如设备编号的连续性、电压的上限等。
- 精度和误差处理:需要处理数值计算中的精度问题,确保最终结果的准确性。
- 迭代设计考虑:题目还提到了后续迭代的设计,这意味着初始设计需要有足够的灵活性和扩展性,以适应未来的变化。
1.3家居强电电路模拟程序-6知识点、题量、难度分析

🐌🐌🐌与先前题目集重复部分的知识点不再赘述
一、计算一个串联电路的总电阻
- 串联电路电阻计算原理:
在串联电路中,总电阻等于各个串联元件电阻之和。 - 开关状态检查:检查开关状态,只计算闭合的分支。
点击查看代码
public double getTotalResistance() {//单条串联电路电阻
double totalResistance = 0;
boolean branchOpen=false;
for (Device device : devices) {
if (device instanceof Switch && ((Switch) device).getState() == 0) {
branchOpen = true;
break; }
if(!branchOpen)
totalResistance += device.CalculateResistance();
else
totalResistance +=0; }
return totalResistance; }
二、递归更新串联电路输入电压、设备状态
对于风扇设备,可能会根据新的电压值重新计算并更新其转速;对于灯泡设备,可能会根据电压值更新其亮度等。
不同类型的设备会在各自的deviceSpecificUpdate更新方法中实现适合自身的状态更新逻辑,所以需要实现在串联电路中对电压的有效传播以及对所有相关设备状态的准确更新。
点击查看代码
//遍历串联电路中的设备并更新电压和状态
public void propagateVoltage(double voltage) {
//...
device.voltage = voltage;///更新输入电压
device.deviceSpecificUpdate();//更新设备状态
if (device instanceof SeriesCircuit) {//递归更新串联电路
((SeriesCircuit) device).propagateVoltage(voltage); } } }
它会将传入的电压值设置给当前串联电路对象本身,然后遍历该串联电路所包含的所有设备,为每个设备设置相同的电压值,并调用设备特定的更新方法(deviceSpecificUpdate)来根据新的电压值更新设备自身的状态(例如,对于风扇设备可能会根据电压更新转速等)。
如果某个设备本身也是一个串联电路(通过instanceof判断),则会递归地调用该设备(作为串联电路)的propagateVoltage方法,以继续在其内部的串联电路中传播电压并更新状态。
三、计算并联电路的总电阻
-
电路理论:并联电路中总电阻的计算:并联电路的等效电阻的倒数为各分支电阻的倒数之和
-
初始化变量:
double totalResistanceInverse = 0; int validBranchCount = 0; //用于记录有效分支
boolean branchOpen = false; boolean branchDuan = false;
totalResistanceInverse 初始化为 0,用于累加各分支电阻的倒数。
validBranchCount 初始化为 0,用于记录有效分支的数量(即开关闭合且电阻不为0的分支)。
branchOpen 和 branchDuan 初始化为 false,用于标记分支是否开路或短路。
遍历电路分支:
for (SeriesCircuit seriesCircuit : seriesCircuits) { for (Device device : seriesCircuit.devices) { //...} }
外层循环遍历所有串联电路分支 seriesCircuits。
内层循环遍历每个分支中的设备 devices。
检查开关状态:
点击查看代码
if (device instanceof Switch && ((Switch) device).getState() == 0) {
branchOpen = true;
break;
}else if(device instanceof Switch && ((Switch) device).getState() != 0&&seriesCircuit.getTotalResistance()==0) {
branchDuan = true;
break;
}
点击查看代码
double seriesResistance = seriesCircuit.getTotalResistance();
if (!branchOpen && seriesResistance != 0) {
totalResistanceInverse += 1 / seriesResistance;
validBranchCount++;
}
}
if (validBranchCount > 0 && totalResistanceInverse != 0&&!branchDuan) { return 1 / totalResistanceInverse; } else { return 0; }
如果存在有效分支且 totalResistanceInverse 不为0且没有短路(!branchDuan),则返回总电阻的倒数(即 1 / totalResistanceInverse)。
如果没有有效分支或 totalResistanceInverse 为0或存在短路,则返回0。
-
输入信息种类与复杂度:
本题的输入信息种类繁多,涵盖了设备信息、连接信息、控制设备调节信息、电源接地标识以及串联电路信息、并联电路信息等。每种信息都有其特定的格式要求,例如设备信息需用特定标识符加编号表示,连接信息要用特定格式的方括号括起来并以空格分隔引脚等。这些多样且格式严格的输入信息增加了输入处理的工作量和复杂度。
从输入样例可以看出,即使是相对简单的示例,也需要输入多条不同类型的信息来完整描述电路的连接、设备配置及控制操作等情况。随着电路规模的增大和功能复杂性的提高,输入信息的量和复杂程度会相应增加。 -
设备与电路情况多样性:
模拟的设备类型丰富,包括多种控制设备(开关、分档调速器、连续调速器)和受控设备(白炽灯、日光灯、吊扇、落地扇),每种设备都有各自不同的工作特性、参数范围及状态变化规则。例如,不同类型的风扇在不同电压区间有不同的转速对应关系,灯具的亮度也根据电位差有不同的计算方式。
电路结构方面,不仅要考虑串联电路,还需处理并联电路以及它们之间的组合情况(虽然本次迭代有一定限制,但仍增加了电路情况的多样性)。不同的电路结构会影响电流、电压在电路中的分布以及设备的工作状态,需要全面考虑各种可能的电路连接方式和设备组合情况。
-
输入解析与逻辑处理:对输入信息的解析要求很高,需要按照严格的格式要求准确提取出设备标识、编号、引脚信息、调节指令等内容,并根据这些信息进行相应的逻辑处理,如更新设备状态、计算输出参数等。处理过程中要考虑各种约束条件(如不考虑某些不合理的电路连接方式、本次迭代的特定限制等),确保程序的正确性和稳定性,这部分的逻辑处理较为细致和复杂。
-
输出格式规范:按照特定的输出格式要求输出所有设备的状态或参数,需要在程序中准确地将计算得到的结果按照规定格式进行整理和输出,包括对连续调速器档位信息保留两位小数等细节要求。这要求在编程过程中对输出部分进行精细处理,稍有不慎就可能导致输出不符合要求。
-
电路计算与状态更新:随着迭代的推进,需要考虑电路计算方式的变化,如从仅考虑简单的电压关系到包含电流、电阻等电路参数的计算。这涉及到更复杂的电路理论知识在程序中的实现,例如根据欧姆定律等计算电流,以及根据电流、电压、电阻的变化更新设备的状态(如风扇转速、灯的亮度等),增加了程序的计算复杂度和逻辑深度。
2. 设计与分析

2.1答题判题程序-4设计与分析
2.1.1.答题判题程序-4的PowerDesigner的uml类图
🎨🎨🎨

类和属性说明:
Question(抽象类)
属性:
int number:题目编号。
String content:题目内容。
String standardAnswer:标准答案。
方法:
int getNumber():获取题目编号。
String getContent():获取题目内容。
String getStandardAnswer():获取标准答案。
boolean checkAnswer(String answer):检查答案是否正确。
MultipleChoiceQuestion(继承自 Question)
方法:
boolean checkAnswer(String answer):重写检查答案的方法,用于处理多选题。
FillInTheBlankQuestion(继承自 Question)
方法:
boolean checkAnswer(String answer):重写检查答案的方法,用于处理填空题。
String evaluateAnswer(String answer):评估填空题答案。
TestPaper
属性:
int number:试卷编号。
List
Map<Integer, Question> questions:题目映射。
Map<Integer, Integer> scores:题目分数映射。
int maxScore:最高分数。
Set
方法:
void addQuestion(int questionNumber, Question question):添加题目。
void addScore(int questionNumber, int score):添加分数。
String getQuestionContent(int questionNumber):获取题目内容。
boolean isTotalScoreCorrect():检查总分是否正确。
List
List
int getScore(int questionNumber):获取题目分数。
Map<Integer, Integer> outScore():输出分数映射。
boolean checkAnswer(int questionNumber, String answer):检查答案。
void deleteQuestion(int questionNumber):删除题目。
Student
属性:
String id:学生ID。
String name:学生姓名。
方法:
String getId():获取学生ID。
String getName():获取学生姓名。
AnswerSheet
属性:
TestPaper paper:关联的试卷。
Map<Integer, String> answers:答案映射。
List
List
List
String studentId:学生ID。
String studentName:学生姓名。
int inputTestNumber:输入的试卷编号。
方法:
void addAnswer(int number, String answer):添加答案。
List
void judgeAnswers():评判答案。
List
String getScoreResults(String studentName):获取分数结果。
类与类之间的关系
继承关系:MultipleChoiceQuestion 和 FillInTheBlankQuestion 继承自 Question。
组合关系:AnswerSheet 包含 TestPaper 对象。
关联关系:TestPaper 包含多个 Question 对象,AnswerSheet 包含学生信息和答案。
2.1.2答题判题程序-4的SourceMonitor的生成报表内容


具体参数分析
- Lines:文件有 702 行代码,表明代码规模较大。
- Statements:共 477 个执行语句数量,可一定程度体现代码的复杂程度和工作量。
- Percent Branch Statements:分支语句占比 25.2%。分支语句通常包括条件判断等,这个比例反映了代码中的逻辑分支情况,较高比例可能意味着代码复杂性增加。
- Method Call Statements:有 340 个方法调用语句,表明代码中对其他方法的调用频繁程度,较多的方法调用可能意味着代码模块化程度较高,但也可能带来性能开销和理解难度。
- Percent Lines with Comments:注释占比 5.3%,可反映代码的可维护性和可读性。较高的注释比例通常意味着代码更容易被理解和维护,但如果比例过高,可能意味着代码自解释性不够好。
- Classes and Interfaces:有 7 个类和接口,说明项目的代码结构较为复杂,有多个不同的功能模块。
- Methods per Class:平均每个类有 5.57 个方法,可反映类的功能划分是否合理。如果一个类的方法过多,可能职责不单一;方法过少,可能功能不完善或可考虑合并类。
- Average Statements per Method:平均每个方法有一定数量的语句,可反映方法的复杂程度。如果一个方法的语句过多,可能意味着这个方法的职责不够单一,应该进行拆分;如果语句过少,可能意味着方法的功能不够完善,或者可以考虑合并一些方法。
- Line Number of Most Complex Method:最复杂方法在第 400 行,为Test.main(),这是程序的入口方法,通常会包含很多的逻辑处理,容易变得复杂。需要注意对这个方法进行优化,将一些逻辑提取到其他方法中,以降低其复杂度。
- Maximum Complexity:最大复杂度为 44,反映了代码的整体复杂程度。复杂度通常是根据代码中的分支、循环、方法调用等因素计算得出的,较高的复杂度意味着代码难以理解和维护,需要进行优化。
- Line Number of Deepest Block:最深代码块在第 349 行,说明在这个位置的代码块嵌套层次最深,可能会影响代码的可读性和可维护性。
- Maximum Block Depth:最大块深度为 9+,反映了代码中嵌套层次的深度,较深的嵌套可能会使代码难以理解和调试,应该尽量减少嵌套层次。
- Average Block Depth:平均块深度为 2.87,这个指标可以反映出代码中嵌套层次的平均深度,同样可以作为代码可读性和可维护性的一个参考指标。
- Average Complexity:平均复杂度为 4.47,可整体反映代码的复杂程度。
2.2家居强电电路模拟程序-5设计与分析
2.2.1.家居强电电路模拟程序-5的PowerDesigner的uml类图
🎨🎨🎨

类和属性说明:
类名:Device
类属性:
id:String类型,设备的标识符。
number:int类型,设备的编号。
voltage:double类型,默认值为0,表示设备的电压。
connectedDevices:List
类方法:
Device(String id, int number):构造函数,无返回类型。
double getVoltage():返回设备的电压。
void addConnection(Device device):添加一个连接的设备,无返回类型。
protected void deviceSpecificUpdate():更新设备特定状态的方法,子类可以覆盖,无返回类型。
类名:Switch(继承自Device)
类属性:
state:boolean类型,表示开关的状态(开或关)。
类方法:
Switch(int number):构造函数,无返回类型。
void toggle():切换开关状态,无返回类型。
int getState():返回开关的状态(1表示开,0表示关)。
类名:FourSpeed(继承自Device)
类属性:
speedLevel:int类型,表示分档调速器的档位。
类方法:
FourSpeed(int number):构造函数,无返回类型。
void increaseSpeed():增加调速器的档位,无返回类型。
void decreaseSpeed():减少调速器的档位,无返回类型。
int getSpeedLevel():返回调速器的档位。
double getOutputVoltage():返回调速器的输出电压。
类名:ContinuousSpeed(继承自Device)
类属性:
speedLevel:double类型,表示连续调速器的档位。
类方法:
ContinuousSpeed(int number):构造函数,无返回类型。
void setSpeedLevel(double level):设置调速器的档位,无返回类型。
double getSpeedLevel():返回调速器的档位。
double getOutputVoltage():返回调速器的输出电压。
类名:Bulb(继承自Device)
类属性:
brightness:int类型,表示灯泡的亮度。
类方法:
Bulb(int number):构造函数,无返回类型。
protected void deviceSpecificUpdate():更新灯泡的亮度,无返回类型。
int getBrightness():返回灯泡的亮度。
类名:FluorescentTube(继承自Device)
类属性:
brightness:int类型,表示日光灯的亮度。
类方法:
FluorescentTube(int number):构造函数,无返回类型。
protected void deviceSpecificUpdate():更新日光灯的亮度,无返回类型。
int getBrightness():返回日光灯的亮度。
类名:Fan(继承自Device)
类属性:
speed:double类型,表示风扇的转速。
类方法:
Fan(int number):构造函数,无返回类型。
protected void deviceSpecificUpdate():更新风扇的转速,无返回类型。
double getSpeed():返回风扇的转速。
类名:SmartHomeSimulator
类属性:
devices:Map<String, Device>类型,存储所有设备。
类方法:
void addDevice(Device device):添加一个设备,无返回类型。
void addConnection(String fromType, int fromNumber, String toType, int toNumber):添加设备之间的连接,无返回类型。
void control(String command):根据控制命令操作设备,无返回类型。
void simulate():模拟智能家居系统,无返回类型。
private int compareDeviceType(Device d1, Device d2):比较两个设备的类型顺序。
类与类之间的关系
继承关系:Switch、FourSpeed、ContinuousSpeed、Bulb、FluorescentTube、Fan都继承自Device类。
组合关系:SmartHomeSimulator包含一个Map,其中键是设备标识符,值是Device对象,表示系统中的所有设备。
2.2.2家居强电电路模拟程序-5的SourceMonitor的生成报表内容



具体参数分析
- Lines:文件有 469 行代码。
- Statements:共 316 个语句。
- Percent Branch Statements:分支语句占比 26.3%。
- Method Call Statements:有 164 个方法调用语句,表明代码中对其他方法的调用频繁程度,较多的方法调用可能意味着代码模块化程度较高,但也可能带来性能开销和理解难度。
- Percent Lines with Comments:注释占比 4.3%,可反映代码的可维护性和可读性。较高的注释比例通常意味着代码更容易被理解和维护,但如果比例过高,可能意味着代码自解释性不够好。
- Classes and Interfaces:未明确具体数量,但从后续内容可推断有多个类。
- Methods per Class:平均每个类有 8.19 个方法,可反映类的功能划分是否合理。如果一个类的方法过多,可能职责不单一;方法过少,可能功能不完善或可考虑合并类。
- Maximum Complexity:最大复杂度为 33,反映了代码的整体复杂程度。复杂度通常根据代码中的分支、循环、方法调用等因素计算得出,较高的复杂度意味着代码难以理解和维护。
- Line Number of Most Complex Method:最复杂方法在第 347 行,为Main.main(),这是程序入口方法,通常包含很多逻辑处理,容易变得复杂,需要重点关注和优化。
- Line Number of Deepest Block:最深代码块在第 248 行,说明此位置的代码块嵌套层次最深,可能影响代码可读性和可维护性。
- Maximum Block Depth:最大块深度为 8,反映了代码中嵌套层次的深度,较深的嵌套可能使代码难以理解和调试,应尽量减少嵌套层次。
- Average Block Depth:平均块深度为 2.98,可作为代码可读性和可维护性的参考指标。
- Average Complexity:平均复杂度为 3.94,可整体反映代码的复杂程度。
2.3家居强电电路模拟程序-6设计与分析
2.3.1.家居强电电路模拟程序-6的PowerDesigner的uml类图
🎨🎨🎨

类和属性说明
Device
属性:
id: String
number: int
voltage: double
resistance: double
connectedDevices: List
方法:
Device(String id, int number, double resistance): 构造函数
getVoltage(): double
addConnection(Device device): void
getOutputVoltage(): double
deviceSpecificUpdate(): protected void
getInfo(): String
getContainingSeriesCircuit(): SeriesCircuit
CalculateResistance(): double
Switch
属性:
state: boolean
方法:
Switch(int number): 构造函数
toggle(): void
getState(): int
getInfo(): String
FourSpeed
属性:
speedLevel: int
方法:
FourSpeed(int number): 构造函数
increaseSpeed(): void
decreaseSpeed(): void
getSpeedLevel(): int
getOutputVoltage(): double
getInfo(): String
ContinuousSpeed
属性:
speedLevel: double
方法:
ContinuousSpeed(int number): 构造函数
setSpeedLevel(double level): void
getSpeedLevel(): double
getOutputVoltage(): double
getInfo(): String
Bulb
属性:
brightness: int
方法:
Bulb(int number): 构造函数
deviceSpecificUpdate(): protected void
getBrightness(): int
getInfo(): String
FluorescentTube
属性:
brightness: int
方法:
FluorescentTube(int number): 构造函数
deviceSpecificUpdate(): protected void
getBrightness(): int
getInfo(): String
Fan
属性:
speed: double
方法:
Fan(int number): 构造函数
deviceSpecificUpdate(): protected void
getSpeed(): double
getInfo(): String
FloorFan
属性:
speed: double
方法:
FloorFan(int number): 构造函数
deviceSpecificUpdate(): protected void
getSpeed(): double
getInfo(): String
SeriesCircuit
属性:
devices: List
方法:
SeriesCircuit(int number): 构造函数
addDevice(Device device): void
getTotalResistance(): double
propagateVoltage(double voltage): void
getContainingSeriesCircuit(): SeriesCircuit
deviceSpecificUpdate(): protected void
ParallelCircuit
属性:
seriesCircuits: List
方法:
ParallelCircuit(int number): 构造函数
addSeriesCircuit(SeriesCircuit circuit): void
handleShortCircuit(): void
CalculateResistance(): double
SmartHomeSimulator
属性:
devices: Map<String, Device>
方法:
addDevice(Device device): void
getDevice(String id, int number): Device
addConnection(String fromType, int fromNumber, String toType, int toNumber): void
control(String command): void
simulate(): void
compareDeviceType(Device d1, Device d2): int
类与类之间的关系
继承关系:
Switch、FourSpeed、ContinuousSpeed、Bulb、FluorescentTube、Fan、FloorFan、SeriesCircuit、ParallelCircuit 继承自 Device 类。
组合关系:
SmartHomeSimulator 包含一个 Map<String, Device> 类型的 devices 属性,表示 SmartHomeSimulator 类管理着所有设备的集合。
SeriesCircuit 包含一个 List
ParallelCircuit 包含一个 List
2.3.2家居强电电路模拟程序-6的SourceMonitor的生成报表内容




具体参数分析
- Lines:文件一共有 682 行代码。
- Statements:有 429 个执行语句数量。
- Percent Branch Statements:分支语句占比 26.6%。
- Method Call Statements:方法调用语句有 170 个,表明代码中对其他方法的调用频繁程度,较多的方法调用可能意味着代码的模块化程度较高,但也可能带来一定的性能开销和理解难度。
- Percent Lines with Comments:注释占比 9.2%,这个比例可以反映出代码的可维护性和可读性。较高的注释比例通常意味着代码更容易被其他人理解和维护,但如果注释比例过高,可能也意味着代码的自解释性不够好,需要过多的注释来解释。
- Classes and Interfaces:有 12 个类和接口,说明项目的代码结构较为复杂,有多个不同的功能模块。
- Methods per Class:平均每个类有 4 个方法,这个指标可以反映出类的功能划分是否合理。如果一个类的方法过多,可能意味着这个类的职责不够单一,应该进行拆分;如果方法过少,可能意味着类的功能不够完善,或者可以考虑合并一些类。
- Average Statements per Method:平均每个方法有 8.35 个语句,这个指标可以反映出方法的复杂程度。如果一个方法的语句过多,可能意味着这个方法的职责不够单一,应该进行拆分;如果语句过少,可能意味着方法的功能不够完善,或者可以考虑合并一些方法。
- Line Number of Most Complex Method:最复杂方法的行号是 563,说明在这个位置的方法可能是代码中最复杂的部分,需要重点关注和优化。
Name of Most Complex Method:最复杂方法是Main.main(),这是程序的入口方法,通常会包含很多的逻辑处理,容易变得复杂。需要注意对这个方法进行优化,将一些逻辑提取到其他方法中,以降低其复杂度。 - Maximum Complexity:最大复杂度为 29,这个指标可以反映出代码的整体复杂程度。复杂度通常是根据代码中的分支、循环、方法调用等因素计算得出的,较高的复杂度意味着代码难以理解和维护,需要进行优化。
- Line Number of Deepest Block:最深代码块的行号是 490,说明在这个位置的代码块嵌套层次最深,可能会影响代码的可读性和可维护性。
- Maximum Block Depth:最大块深度为 8,这个指标反映了代码中嵌套层次的深度,较深的嵌套可能会使代码难以理解和调试,应该尽量减少嵌套层次。
- Average Block Depth:平均块深度为 2.81,这个指标可以反映出代码中嵌套层次的平均深度,同样可以作为代码可读性和可维护性的一个参考指标。
3. 采坑心得

🤗🤗🤗
- 我希望我的这些坑,都不白踩,也希望如果大家遇到了相似的问题,我的解决方法真的能够帮到你🤗。
3.1答题判题程序-4采坑心得

点击查看代码
if (line.startsWith("#N:")) {
//...
}else if (line.startsWith("#T:")) {
testPaper.addScore(questionNumber, scoreValue);
testPaper.addQuestion(questionNumber, allQuestions.get(questionNumber));
//...
}
- 当输入格式以"#T:"开头时,首先将试卷编号存储在testPaperNumbers列表中。这一步是为了在所有输入完成后,能够遍历所有试卷并处理缺失的题目。
调用processTestPaperLine方法来处理试卷信息,解析试卷编号、题目编号和分值,并将它们添加到TestPaper对象中。
在processTestPaperLine方法中,对于每个题目编号,首先检查allQuestions映射中是否已经存在该题目。如果不存在,说明题目信息尚未输入,或者输入顺序导致题目信息在试卷信息之后。
如果题目不存在,将题目编号添加到missingQuestions映射中,该映射以试卷编号为键,缺失题目编号列表为值。这允许程序在所有输入完成后处理这些缺失的题目。
如果题目存在,使用addQuestion方法将其添加到TestPaper对象中。这包括了题目对象和对应的分值。
在所有输入完成后,程序遍历testPaperNumbers列表,对于每个试卷编号,检查missingQuestions映射中是否有缺失的题目编号。
对于每个缺失的题目编号,再次检查allQuestions映射,看题目信息是否已经存在。如果存在,将题目添加到对应的TestPaper对象中;如果不存在,将null添加到TestPaper对象中,表示该题目无效或不存在。
当输入中出现"end"时,程序将停止读取更多输入,并开始处理已经收集的数据,包括将缺失的题目添加到试卷中。
点击查看代码
else if (line.startsWith("#T:")) {
testPaperNumbers.add(testNumber); // 记录试卷编号
processTestPaperLine(Zcount,line, testPapers, allQuestions, missingQuestions);
//...
}
//...
for (Integer questionNumber : missingQuestionNumbers) {
Question question = allQuestions.get(questionNumber);
testPaper.addQuestion(questionNumber, question); }
private static void processTestPaperLine(){
//...
if (!allQuestions.containsKey(questionNumber)) {
List<Integer> missingQuestionNumbers = missingQuestions.computeIfAbsent(testNumber, k -> new ArrayList<>());
missingQuestionNumbers.add(questionNumber);
} else {
testPaper.addQuestion(questionNumber, allQuestions.get(questionNumber)); }
}
当试卷信息比题目信息先输入时,会出现该题目不存在的情况

改正后能够在乱序输入情况下,正确在试卷中存入题目信息

点击查看代码
public String evaluateAnswer(String answer) {
//...
String standard = getStandardAnswer();
if (answer.equals(standard)) {
return "true";
} else if (standard.contains(answer) || answer.contains(standard)) {
return "partially correct";
} else {
return "false";
}
}
修改后代码,answer.split("或")、standard.split("或")将标准答案和学生答案都按照"或"字拆分成多个可能的正确答案,这样可以处理多种表述的情况。
检查答案是否与标准答案完全相同,如果是,则设置isExactMatch为true并跳出循环。
如果答案中的每个部分都包含在标准答案的对应部分中,并且长度相同,则设置isPartialMatch为true。
如果完全匹配或部分匹配的条件都不满足,返回"false"。
点击查看代码
public String evaluateAnswer(String answer) {
//...
for (String part : standardParts) {
if (answer.equals(standard)) { // 找到完全匹配,无需继续检查
isExactMatch = true;
break; }
for(String anspart : answersParts) {
if (part.contains(answer) && anspart.length() == part.length()) {
isPartialMatch = true; }}}
if (isExactMatch) {
return "true";
} else if (isPartialMatch) {
return "partially correct";
} else {
return "false"; } }}

修正代码能够准确判断部分正确的答案

造成该现象跟判断试卷号是否存在的输出部分有关,在输出部分是对试卷进行遍历判断试卷号是否存在的
boolean paperExists = answerSheet.paper != null && testPapers.get(answerSheet.paper.number) != null;// 判断试卷号是否存在
if (!paperExists) { System.out.println("The test paper number does not exist"); continue; }
当不存在的试卷号不被存储在 currentSheets 中,后续的遍历和排序操作就不会考虑到这个不存在的试卷号。因此,程序不会输出关于不存在试卷号的任何提示信息。
原代码:
if (testPaper == null) { return; } // 如果试卷不存在不存储试卷
answerSheet = currentSheets.computeIfAbsent(testNumber, k -> new AnswerSheet(testPaper, studentId,testNumber));
原代码逻辑中,问题在于,它在检测到试卷号不存在时直接终止了处理流程,没有给程序一个机会去记录这个错误并在后面的流程中处理它。
修改后代码:
点击查看代码
if (testPaper == null) {
// 创建一个特殊的AnswerSheet对象表示错误情况,这里假设AnswerSheet有一个构造函数可以传入错误信息
answerSheet = new AnswerSheet(null, parts[1].trim(),testNumber);
currentSheets.computeIfAbsent(testNumber, k -> answerSheet);
return;
}

原代码中,输入试卷号不存在的答卷后,输出信息没有提示该试卷号不存在

走到这里,答题判题程序-4的编程部分完结撒花喽🐾🐾🐾
3.2家居强电电路模拟程序-5采坑心得

List<Device> sortedDevices = new ArrayList<>(devices.values());
sortedDevices.sort((d1, d2) -> d1.number - d2.number);
原代码中,只根据设备的编号进行排序,而不考虑设备的类型。这意味着所有设备将按照它们的编号顺序排列,不论它们是什么类型的设备。
改正后代码,使用了自定义的compareDeviceType方法来比较设备的类型,并根据类型和编号进行排序。定义Map<String, Integer>类型的变量,它存储了设备类型的字符串标识符(如"K"、"F"等)和它们对应的排序整数(如1、2等),首先根据设备的类型(id)来确定排序顺序。如果两个设备的类型不同,它们将根据预定义的类型顺序(typeOrder)进行排序。如果类型相同(即typeOrder返回0),则按照设备的编号(number)进行排序。
点击查看代码
private int compareDeviceType(Device d1, Device d2) {
String type1 = d1.id;
String type2 = d2.id;
Map<String, Integer> typeOrder = new HashMap<>();
typeOrder.put("K", 1);
typeOrder.put("F", 2);
//...
int order1 = typeOrder.getOrDefault(type1, 7);//获取设备类型type1对应的排序顺序。如果type1在typeOrder映射中有定义,getOrDefault方法将返回与type1关联的排序整数。如果type1不在映射中,它将返回默认值7。
int order2 = typeOrder.getOrDefault(type2, 7);
return Integer.compare(order1, order2);
}
按照以下输入,原代码的开关K输出顺序错误,没有实现设备类型先后顺序排序

改正后,能够按开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇的顺序依次输出所有设备的状态或参数,同类设备按编号顺序从小到大输出

原代码中没有检查串联电路中所有开关的状态,一旦有一个开关闭合就直接输出风扇的不为0速度,没有考虑电路的实际连接状态,无视了除闭合开关以外的其他开关状态。
System.out.println("@" + device.id + device.number + ":" + (int) fan.getSpeed());//D
改正后,首先初始化一个布尔变量allSwitchesOn为true,表示所有开关默认都是开启的。然后,通过遍历所有已排序的设备sortedDevices,检查每个设备是否为Switch类型。如果是,并且开关的状态为0(关闭),则将allSwitchesOn设置为false并跳出循环。最后,如果allSwitchesOn为false,则将风扇的速度fan.speed设置为0,表示风扇停止转动。之后,输出风扇的状态。它包含了必要的逻辑来检查所有开关状态,并根据开关状态调整风扇速度。
点击查看代码
boolean allSwitchesOn = true;
for (Device device : sortedDevices) {
if (device instanceof Switch) {
Switch switchDevice = (Switch) device;
if (switchDevice.getState()==0) {
allSwitchesOn = false;
break; } } }
if (!allSwitchesOn) { fan.speed = 0; }
System.out.println("@" + device.id + device.number + ":" + (int) fan.getSpeed());//D
原代码没有检测所有开关状态,直接输出风扇速度,导致在有开关断开的情况下错误地输出风扇速度。

改正后,在输出风扇状态之前考虑了所有开关的状态,根据电路情况正确输出风扇速度

原代码没有考虑风扇是否直接连接到电源,一旦受控设备直接接地,会直接输出初始状态下的设备状态值0
点击查看代码
public Fan(int number) {
//...
this.speed = 0; }
// 输出设备状态
点击查看代码
if (device instanceof Fan) {
Fan fan = (Fan) device;
// 检查是否有开关控制这个风扇
boolean isDirectlyConnectedToPower = true;
for (Device connectedDevice : fan.connectedDevices) {
if (connectedDevice instanceof Switch) {
isDirectlyConnectedToPower = false;
break;} }
if (isDirectlyConnectedToPower&&sortedDevices.size()==1){
fan.voltage = 220;
fan.deviceSpecificUpdate(); }}
原代码受控设备直接接地,会直接输出初始状态下的设备状态值0

改正正确后,风扇直接连接到电源,风扇的电压为220,风扇的速度360

3.3家居强电电路模拟程序-6采坑心得

- 🤐
简单地将所有设备的电阻相加来计算总电阻。这实际上是基于纯串联电路的电阻计算方式,它假设所有设备都是依次连接,电流依次通过每个设备,没有支路的情况。
当电路中存在并联部分时,这种方法就不再适用。如果错误地计算包含并联部分的电路总电阻,会得到错误的结果,进而导致分压计算错误,无法正确地根据分压改变设备状态。
double totalResistance = 0;
for (Device device : devices) { totalResistance += device.resistance; }
改进后,getTotalResistance方法考虑了电路的实际连接情况。
点击查看代码
if (device instanceof Switch && ((Switch) device).getState() == 0) {
branchOpen = true;
break; }
if(!branchOpen)
totalResistance += device.CalculateResistance();
else
totalResistance +=0;
这种方法实际上考虑了并联电路的情况。例如,假设有两个支路,一个支路是一个电阻,另一个支路是一个开关和一个电阻串联。当开关断开时,在计算总电阻时就忽略了包含的支路,只考虑所在支路的电阻。
原代码在简单串联电路中准确,但在包含并联或可控制支路的电路中会导致错误的总电阻计算,进而导致分压计算错误,无法正确地根据分压改变设备状态。

改正后能更准确地计算总电阻,尤其是在复杂电路结构下,能为分压计算提供正确的基础,从而更准确地根据分压改变设备状态。

原代码没有考虑电路是否断路,直接进行分压计算。
for (Device device : devices) {
device.voltage = (device.resistance / totalResistance) * totalVoltage;
if (voltage > 0) { device.deviceSpecificUpdate(); } }
简单地根据分压公式来计算每个设备的电压。它没有考虑电路可能因为某些设备(如开关、调速器等)处于断开状态而导致整个电路断路的情况。
例如,当电路中有一个开关断开时,按照第一种方法仍然会计算每个设备的分压,这在实际断路的情况下是不合理的,因为断路后所有设备电压应该为 0。
在复杂电路结构中,不同设备的连接方式(串联、并联)会影响电压的分配和传播。它没有考虑到如果一个并联分支中的串联电路出现断路情况,应该如何正确地将电压设置为 0 并传播这个变化。
改正后的代码中,首先检测电路是否断路,然后根据电路状态来计算或设置设备电压。
点击查看代码
// 检查电路是否因为开关或调速器而断开
for (Device device : devices) {
if (device instanceof Switch && ((Switch) device).getState() == 0) {
circuitOpen = true; break; }
//...
}
- 首先通过一个循环检查电路是否因为某些设备(开关、不同类型的调速器)而断开。这个步骤很关键,因为它能够识别出电路实际的连通状态。例如,如果检测到一个开关处于断开状态(((Switch) device).getState() == 0)或者调速器处于使电路断开的状态(如((ContinuousSpeed) device).getSpeedLevel() == 0等情况),就会将circuitOpen标志设置为true,表示电路是断开的。
点击查看代码
for (Device device : devices) {
if (circuitOpen) {
device.voltage = 0;
//...确保将电压传播到串联电路中的所有设备
}
else {device.voltage = (device.resistance / totalResistance) * totalVoltage; }
device.deviceSpecificUpdate(); }
- 根据circuitOpen的值来分配电压。如果circuitOpen为true,所有设备电压都被设置为 0。对于并联电路中的串联电路部分,还会进一步传播电压为 0 的设置,确保整个相关电路部分都能正确地更新电压。这符合实际电路的情况,因为断路后整个电路不应有电压。
点击查看代码
if (device instanceof ParallelCircuit) {
List<SeriesCircuit> seriesCircuits = ((ParallelCircuit) device).seriesCircuits;
for (SeriesCircuit seriesCircuit : seriesCircuits) {
seriesCircuit.voltage = 0;
// 确保将电压传播到串联电路中的所有设备
seriesCircuit.propagateVoltage(0); } }
- 对于ParallelCircuit并联类型的设备,当电路断开时,它不仅将该设备电压设为 0,还会遍历其中包含的串联分支SeriesCircuit,将它们的电压也设为 0,并通过propagateVoltage方法传播这个电压变化。这种对不同设备类型的细致处理使得它能够更准确地根据电路实际情况改变设备状态,符合复杂电路中电压计算和设备状态更新的要求。
没有考虑电路是否断路,电路正常时可以正确地按照分压公式分配电压,但在电路断路时会出现错误的电压分配。
原代码没有考虑电路是否断路,在主串联电路断路时会出现错误的电压分配。

改正后,调速器处于使电路断开的状态,输入电压直接置0

double totalVoltage = 220; // VCC电压
device.voltage = (device.resistance / totalResistance) * totalVoltage;
没有考虑到电路中的电压调节设备(调速器等)对总电压的影响。在实际电路中,这些设备可以改变施加到电路其余部分的有效输入电压,而始终使用固定的220V计算分压,导致在有电压调节设备的电路中计算出错误的电压值,设备状态更新不正确。
改正后,在计算分压之前,通过对不同类型电压调节设备的处理,动态地更新了totalVoltage,更准确地反映了实际电路中的总电压情况。
针对不同类型的电压调节设备(如Switch、ContinuousSpeed和FourSpeed)进行了特殊处理。
点击查看代码
for (Device device : devices) {
if (device instanceof Switch) {
Switch switchDevice = (Switch) device;
totalVoltage = switchDevice.getState()*totalVoltage;
}
if (device instanceof ContinuousSpeed) {
ContinuousSpeed regulator = (ContinuousSpeed) device;
totalVoltage = regulator.getSpeedLevel()*totalVoltage;
}
if (device instanceof FourSpeed) {
FourSpeed regulator = (FourSpeed) device;
totalVoltage = regulator.getOutputVoltage();
}
}

正确地调整总电压,进而更准确地计算设备电压,这使得它更符合实际电路中电压计算和设备状态更新的要求。

4. 改进建议
- 以下内容是我对自己每个题目代码的优化改进想法🤗:
4.1答题判题程序-4改进建议
- 方法抽取与职责单一原则:
在main方法中,有大量根据输入行的不同前缀进行不同处理的逻辑,导致main方法过长且职责不单一。可以考虑将这些处理逻辑进一步抽取成独立的方法,例如将处理题目信息、试卷信息、学生信息、答卷信息和删除题目信息的逻辑分别封装到不同的私有方法中,使main方法更加清晰简洁,专注于整体流程的控制。
像AnswerSheet类中的judgeAnswers方法,功能较为复杂,可以尝试将其中一些内部的逻辑判断,如处理不同题型答案判断的部分,进一步抽取成更小的私有方法,提高代码的可读性和可维护性。 - 优化集合的使用:
在TestPaper类中,使用了List来存储问题的顺序,Map<Integer, Question>来存储问题编号和对应的问题对象,Map<Integer, Integer>来存储问题编号和对应的分值。可以考虑使用更合适的数据结构来提高性能和简化操作。例如,如果问题的顺序在后续的处理中主要是用于按照顺序遍历问题,那么可以使用LinkedHashSet 来存储问题编号,它既可以保证元素的唯一性,又可以按照插入顺序遍历,这样在添加和遍历问题时可能会更加高效。
在AnswerSheet类中,同样使用了多个List和Map来存储答案、结果、分值等信息。可以根据实际的使用场景,分析是否有更合适的数据结构来优化存储和访问效率。比如,如果需要频繁根据问题编号查找对应的答案和结果,可以考虑使用HashMap<Integer, AnswerInfo>的形式,其中AnswerInfo是一个自定义的类,包含了答案、结果、分值等相关信息,这样可以通过一次哈希查找就获取到所需的全部信息,而不是分别从不同的List和Map中获取。
4.2家居强电电路模拟程序-5改进建议
- 拆分大型方法:
在main方法中,代码逻辑较为复杂且冗长,它承担了过多的职责,包括解析输入、创建设备、添加连接以及控制设备等多种功能。建议将这些不同功能的代码块拆分到独立的方法中,以提高代码的可读性和可维护性。例如,可以创建一个专门用于解析设备信息的方法、一个用于处理连接添加的方法以及一个用于执行控制操作的方法等。 - 类的职责划分:
虽然目前已经有了一定的类层次结构,但部分类的职责可以进一步明确和细化。比如,SmartHomeSimulator类承担了设备管理、连接管理、控制操作以及模拟运行等多种功能,可能会导致这个类变得过于庞大和复杂。可以考虑将一些相关的功能提取出来,形成新的辅助类或者将部分功能下沉到设备类本身,使得每个类的职责更加单一和明确。 - 异常处理:
在整个输入处理过程中,除了进行输入验证外,还应该合理地使用异常处理机制。例如,当尝试从HashMap中获取不存在的设备时(如devices.get(fromType + fromNumber);),如果获取失败,目前代码没有很好的处理方式,可能会导致后续操作出现空指针异常等问题。可以使用try-catch块来捕获这些可能出现的异常,并进行适当的处理,比如给出错误提示或者采取一些默认的恢复操作。 - 设备类型扩展:
随着智能家居系统的发展,可能会有新的设备类型需要添加到模拟器中。目前的代码结构在添加新设备类型时,可能需要在多个地方进行修改,比如在main方法中添加创建新设备的逻辑,在SmartHomeSimulator类的control方法中添加针对新设备的控制操作逻辑等。为了提高代码的可扩展性,可以考虑使用设计模式,比如工厂模式来创建设备对象,使得添加新设备类型时只需要在工厂类中进行相应的修改,而不需要在多个地方改动代码。
4.3家居强电电路模拟程序-6改进建议
- 方法职责划分:
在SeriesCircuit类的deviceSpecificUpdate方法中,功能较为复杂且包含了多层嵌套的逻辑判断和循环操作。可以考虑将其中一些相对独立的功能提取成单独的方法,例如将检查电路是否断开以及根据电路状态设置设备电压的逻辑提取成一个名为updateDeviceVoltagesBasedOnCircuitState的方法,这样可以提高代码的可读性和可维护性,使每个方法的职责更加清晰。 - 性能优化:
在一些场景下,比如设备数量较多时,目前的代码可能会存在性能问题。例如,在SmartHomeSimulator类的simulate方法中对设备列表进行排序的操作,如果设备数量庞大,排序操作可能会消耗较多的时间。可以考虑根据具体的应用场景和需求,对排序算法进行优化,或者采用更适合的排序数据结构来提高排序效率。 - 功能扩展:
除了添加新设备类型,可能还会有新的功能需求,比如增加更多的控制方式、设备之间的新交互方式等。目前的代码结构在面对这些功能扩展时,可能会显得不够灵活。可以通过定义清晰的接口和抽象类,将设备的通用行为和特定行为进行分离,以便在不影响现有代码结构的基础上,更容易地添加新的功能模块。
5. 总结
5.1本阶段三次题目集收获

- 面向对象编程深化
通过设计各种设备类(如Switch、FourSpeed、ContinuousSpeed、Bulb、FluorescentTube、Fan、FloorFan等)以及电路相关类(SeriesCircuit、ParallelCircuit),深入理解了类的继承、多态性和封装特性。
例如,不同类型的设备类继承自Device基类,并重写了deviceSpecificUpdate方法以根据自身特性响应电压变化,这体现了多态性的应用。同时,将设备的属性和操作封装在各自的类中,使得代码结构更加清晰,易于维护和扩展。
掌握了在复杂系统中处理设备之间连接关系的方法,如通过addConnection方法建立设备之间的连接,并在电路类(SeriesCircuit、ParallelCircuit)中实现电压传播和设备状态更新的逻辑。这有助于构建具有层次结构和交互性的系统模型,提高了对面向对象设计模式中组合和聚合关系的运用能力。
- 电路原理与编程结合
理解了分压法计算电压的原理,并将其应用于程序中,根据设备电阻与总电阻的比例来确定各个设备的电压。这需要对电路基本概念有清晰的认识,并能够将其转化为代码逻辑,实现了电路知识与编程实践的有效结合。
例如,在计算串联电路总电阻和各设备电压时,考虑了开关状态对电路连通性的影响,以及不同类型调速器对总电压的调节作用,进一步加深了对电路分析和计算的理解。
学会了处理电路中的多种情况,如开关的通断、调速器的不同挡位设置以及短路情况的判断和处理。在SeriesCircuit和ParallelCircuit类中,通过对设备状态的检查和相应的计算逻辑,能够准确地模拟电路在不同工况下的行为,提高了对复杂电路系统的建模和控制能力。
5.2深入学习探究的思考

-
性能优化
在当前的电路模拟实现中,对于大型复杂电路的计算效率可能较低。例如,在计算总电阻和电压传播时,可能存在一些重复计算的情况。可以考虑采用缓存机制,存储已经计算过的电路参数(如总电阻、部分电路的电压值等),以减少不必要的重复计算,提高程序的运行速度。
对于大规模电路,还可以研究并行计算技术的应用,将电路的不同部分分配到多个处理器核心或计算单元上进行并行计算,进一步提高计算效率。例如,在计算并联电路各分支的电阻和电压时,可以并行处理各个分支的计算任务,然后汇总结果。 -
新设备类型的添加
随着智能家居系统的发展,可能会有更多新型设备需要集成到电路模拟系统中。为了便于添加新设备类型,目前的代码结构可以进一步优化。例如,可以采用工厂模式或抽象工厂模式来创建设备对象,根据设备类型的标识动态创建相应的设备实例,这样在添加新设备类型时只需修改工厂类的代码,而不会影响到系统的其他部分。
对于新设备的功能和特性,需要考虑如何与现有电路模拟框架进行无缝集成。例如,新设备可能具有特殊的通信接口或控制逻辑,需要设计合适的接口和抽象类,以便在不破坏现有代码结构的前提下将其纳入系统中,并确保其能够正确地与其他设备进行交互和协同工作。
5.3问题改进与建议

- 对教师、课程、作业、实验、课上及课下组织方式等方面的改进建议及意见:
- 建立作业反馈机制,给予学生详细的反馈意见。指出学生作业中的错误和不足之处,提供正确的解决方案和改进建议,帮助学生理解自己的问题所在并进行改进。🤕🤕🤕
- 同时,可以组织学生进行作业交流和讨论,让学生分享自己的作业思路和解决方案,互相学习和借鉴,拓宽学生的思维方式和解决问题的方法。😎😎😎
欢迎大家给我好的编程建议或者学习思路,希望我们的程序都一把过🐱🏍


浙公网安备 33010602011771号