一、前言
相关知识点:
1、家居强电电路模拟程序-3在上一次的基础上增加了互斥开关,互斥开关只有两种状态:开关接往上面的2号引脚、接往下面的3号引脚。开关每次只能接通其中一个分支引脚,而另一个分支引脚处于断开状态。为避免短路,互斥开关设置了限流电阻,12引脚之间默认电阻为5,13引脚之间默认电阻为10。还增加了受控窗帘,不考虑室外光照强度和室内空间大小等因素,窗帘受室内灯光的光照强度控制。本次迭代考虑多个并联电路串联在一起的情况。
2、家居强电电路模拟程序-4在家居强电电路模拟程序-3的基础上增加了二极管,增加二极管元件,其电路特性为:正向导通,反向截止;其电器符号如图4所示,当电流从左至右流过时,二极管导通”conduction”,电阻为0;电流从右至左流动时,二极管截止”cutoff”,电阻无穷大,相当于开关打开。增加管脚电压的显示,在输出每个电器的状态信息后,再依次输出该电器每个管脚的电压。电器在工作时,过大的电流会引起电器过热,从而烧坏电路。本次迭代,每个元器件都有最大电流的设置,当实时电流超过最大电流时,在该电器输出信息的最后加入提示“exceeding current limit error”,与前面的信息之间用英文空格分隔。
题量:
这两次题目集都只有一道题,题量并不多,但是难度很大。
难度:
这两次题目集的难度直线上升,与之前可谓是天差地别,之前的题目集在努力后能够写出来但是这两次的题目集实在是让我无从下手,有了大概的思路但是当动手时却又不知从何处开始修改,当然这也和我之前的考虑不周有关,导致在添加新的代码时十分麻烦,需要改的地方很多,在家居强电电路模拟程序-3中新增了引入多条并联电路串联起来,难度增加。互斥开关可以出现在两条电路中。,在家居强电电路模拟程序-4中新增了引入并联电路里面有并联电路,难度增加,并且需要输出引脚电压,需要计算电流,在编程的同时,还需要考验我本来就不好的电路知识。难度剧增。
二、设计与分析
1、家居强电电路模拟程序-3
多个设备类继承自Device类(例如Switch、MutexSwitch、FourSpeed、ContinuousSpeed、Bulb、FluorescentTube、Fan、FloorFan、Curtain、Diode等),通过extends关键字实现继承关系。子类继承了父类的属性(如id、number、voltage等)和方法(如构造函数等)。
javascript
class MutexSwitch extends Device; // 互斥开关
class FourSpeed extends Device; // 分档调速器
Switch类继承自Device类,获得了父类的属性和方法。在构造函数中,子类通过调用super()初始化父类的基本属性。此外,Switch类还定义了state属性来表示开关状态(开或关),并定义了toggle方法用于切换状态,getState方法用于获取当前状态,扩展了智能家居电路中开关的特殊操作逻辑。
MutexSwitch类实现了互斥开关功能,控制引脚状态并提供相关操作;
FourSpeed和ContinuousSpeed类分别实现了不同类型的调速器,包含调速相关方法;
Bulb、FluorescentTube等照明设备类实现了特有的deviceSpecificUpdate方法,用于根据电压更新亮度;
Fan和FloorFan风扇类则实现了根据电压更新转速的逻辑;
Curtain类管理窗帘的开合百分比,并包含相应的逻辑;
Diode类根据电压判断导通与截止状态。
所有这些设备类都继承自Device类,通过复用通用设备的属性和基础方法,各自扩展了符合自身特性的方法和属性。这种继承机制使得在智能家居模拟系统中能够统一管理和操作不同类型的设备,体现了继承在代码复用、功能扩展和面向对象设计中的作用。这样,代码结构更加清晰,易于理解和维护。
在SeriesCircuit类的getTotalResistance方法中,遍历了devices列表。该列表中的元素都是Device类型,但实际存储的对象可能是ParallelCircuit、SeriesCircuit或其他继承自Device的子类(如Bulb、Fan等)。当调用CalculateResistance方法时,程序根据对象的实际类型选择执行相应子类中重写的CalculateResistance方法,这体现了多态性。
例如,如果设备是ParallelCircuit类型,系统会调用ParallelCircuit类中重写的CalculateResistance方法来计算并联电路的等效电阻并累加到总电阻中;如果是SeriesCircuit类型,则调用SeriesCircuit类中计算串联电路总电阻的方法;对于其他普通设备(如Bulb、Fan等),则执行Device类中定义的CalculateResistance方法(可能直接返回设备的电阻值)。通过这种方式,系统能够根据对象的实际类型来决定调用哪个具体的方法,从而增强了代码的灵活性和可扩展性。
该题目的类图:
-
抽象类 Device
作用:Device 是所有电路设备的父类,定义了共享的属性和方法。作为一个抽象类,它不能直接实例化。数据成员:
String name:设备名称。
double resistance:电阻值。
double current:电流。
double electricity:电量。
double potential:设备电压。
double potential1 和 double potential2:设备两端引脚的电压。
String pin1 和 String pin2:设备的两个引脚名称。
int location:设备在电路中的位置。
boolean decide:辅助标志位,用于标记设备的特定状态。
方法成员:构造方法:
Device():默认构造方法。
Device(String name, String pin1, String pin2):带参数的构造方法,用于初始化设备名称和引脚。
String getName():返回设备的名称。类关系:Device 被其他设备类继承。
抽象类 ControlDevice
作用:ControlDevice 是所有控制类设备的基类,派生出具体的控制设备,如开关、调速器等。数据成员:
继承自 Device,无新增成员。
方法成员:构造方法:
ControlDevice():默认构造方法。
ControlDevice(String name, String pin1, String pin2):带参数的构造方法,用于初始化名称和引脚。
抽象方法:void setState(String num):设置设备状态的方法。
类关系:ControlDevice 继承自 Device,并被具体的控制设备(如 Switch, BinningGovernor 等)继承。类 Switch
作用:表示一个开关设备,通过 state 属性控制电路的开关状态。数据成员:
boolean state:开关的开/关状态。
方法成员:构造方法:
Switch():默认构造方法。
Switch(String name, String pin1, String pin2):初始化开关名称和引脚。
boolean isState():返回当前开关状态。String getState():返回状态描述字符串(例如:"closed" 或 "turned on")。
void setState(String num):切换开关状态。
String toString():返回开关的状态、电压和电流信息。
类关系:继承自 ControlDevice。
类 MutexSwitches
作用:表示互斥开关,用于控制多个电路的互斥逻辑。数据成员:
boolean state:互斥开关的状态。
String pin3:第三引脚名称。
double potential3:第三引脚的电势。
double electricity1:通过第三引脚的电流。
方法成员:构造方法:
MutexSwitches():默认构造方法。
MutexSwitches(String name, String pin1, String pin2):初始化互斥开关名称和引脚。
boolean isState():返回当前状态。String getState():返回状态描述字符串。
void setState(String num):切换开关状态。
String toString():返回互斥开关的状态及相关电气信息。
类关系:继承自 ControlDevice。
类 BinningGovernor
作用:表示分档调速器,可以通过档位来调节输出电压。数据成员:
int gears:当前档位。
double voltage:输出电压。
方法成员:构造方法:
BinningGovernor():默认构造方法。
BinningGovernor(String name, String pin1, String pin2):初始化调速器名称和引脚。
double getOutputVoltage(double num):根据档位和输入电压计算输出电压。void setVoltage(int voltage):设置输出电压。
int getGears():获取当前档位。
void setGears(int gears):设置档位。
void setState(String num):根据输入调整档位。
String toString():返回档位状态及相关信息。
类关系:继承自 ControlDevice。
类 ContinuousGovernor
作用:表示连续调速器,支持精细调整输出电压。数据成员:
double gears:当前档位。
double voltage:输出电压。
方法成员:构造方法:
ContinuousGovernor():默认构造方法。
ContinuousGovernor(String name, String pin1, String pin2):初始化调速器名称和引脚。
double getOutputVoltage(double num):根据档位和输入电压计算输出电压。void setGears(double gears):设置档位。
double getGears():获取当前档位。
void setState(String num):设置档位。
String toString():返回调速器的状态及相关信息。
类关系:继承自 ControlDevice。
抽象类 ControlledDevice
作用:ControlledDevice 是所有受控设备的基类,派生出具体的受控设备,如灯具、电风扇等。数据成员:
继承自 Device,无新增成员。
方法成员:构造方法:
ControlledDevice():默认构造方法。
ControlledDevice(String name, String pin1, String pin2):初始化名称和引脚。
抽象方法:void setPotential():设置设备的电势。
类关系:继承自 Device,并被具体的受控设备(如 Incandescent, Fluorescent 等)继承。类 Incandescent
作用:表示白炽灯,根据电压来计算亮度。数据成员:
double brightness:灯的亮度。
方法成员:构造方法:
Incandescent():默认构造方法。
Incandescent(String name, String pin1, String pin2):初始化灯具名称和引脚。
double getBrightness():获取亮度。void setBrightness(double brightness):设置亮度。
void setPotential():根据电压计算亮度。
String toString():返回灯具的状态及相关信息。
类关系:继承自 ControlledDevice。
类 Fluorescent
作用:表示日光灯,根据电压计算亮度。数据成员:
double brightness:灯的亮度。
方法成员:构造方法:
Fluorescent():默认构造方法。
Fluorescent(String name, String pin1, String pin2):初始化灯具名称和引脚。
double getBrightness():获取亮度。void setBrightness(int brightness):设置亮度。
void setPotential():根据电压计算亮度。
String toString():返回灯具的状态及相关信息。
类关系:继承自 ControlledDevice。
类 CeilingFan
作用:表示吊扇,根据电压计算风扇的速度。数据成员:
int speed:风扇速度。
方法成员:构造方法:
CeilingFan():默认构造方法。
CeilingFan(String name, String pin1, String pin2):初始化风扇名称和引脚。
int getSpeed():获取风扇速度。void setPotential():根据电压计算风扇速度。
String toString():返回风扇的状态及相关信息。
类关系:继承自 ControlledDevice。
类 Floorfan
作用:表示落地扇,与吊扇类似,根据电压计算风扇速度。数据成员:
int speed:风扇速度。
方法成员:与 CeilingFan 类相同。
类关系:继承自 ControlledDevice。类 ControlledCurtains
作用:表示智能窗帘,控制窗帘的开合比例。数据成员:
String proportion:窗帘的开合比例。
double brightness:窗帘的亮度。
方法成员:构造方法:
ControlledCurtains():默认构造方法。
ControlledCurtains(String name, String pin1, String pin2):初始化窗帘名称
关键方法
double calculateVoltage(Device device, double inputVoltage)
:计算设备上的电压。void processControlCommand(String command)
:处理控制命令,如切换开关状态或调整调速器档位。void parseAndAddConnection(String connectionInfo, Circuit circuit)
:解析连接信息并添加到电路中。void simulateCircuit()
:模拟整个电路,计算并输出所有设备的状态。
以上三个类以及调用他们的部分Main函数。
// 伪代码示例
public class Main {
public static void main(String[] args) {
List<Circuit> circuits = new ArrayList<>();
// 读取输入并构建电路
while (true) {
String line = readInput();
if (line.equals("end")) break;
if (line.startsWith("#T")) {
// 处理串联电路
SeriesCircuit seriesCircuit = new SeriesCircuit();
seriesCircuit.parseAndAddConnection(line);
circuits.add(seriesCircuit);
} else if (line.startsWith("#M")) {
// 处理并联电路
ParallelCircuit parallelCircuit = new ParallelCircuit();
parallelCircuit.parseAndAddConnection(line);
circuits.add(parallelCircuit);
} else {
// 处理控制命令
processControlCommand(line);
}
}
// 模拟电路并输出结果
simulateCircuits(circuits);
}
private static void simulateCircuits(List<Circuit> circuits) {
// 遍历所有电路,计算每个设备的状态
for (Circuit circuit : circuits) {
circuit.simulate();
}
// 输出所有设备的状态
printDeviceStates();
}
}
SourceMonitor分析如下:
- 复杂度分析
整个项目中,Main.main()方法的复杂度最高,达到了37,语句数也较多,有93个语句,这可能是一个需要重点关注和优化的方法。
平均复杂度为3.85,说明整体代码的复杂度处于中等水平,但有一些方法的复杂度较高,可能会影响代码的可读性和维护性。 - 代码规模
代码行数达到1,100行,语句数为627,这表明项目有一定的规模。 - 注释情况
带注释的代码行百分比为13.3,说明代码中的注释相对较少,可能需要增加注释来提高代码的可读性。 - 方法调用
方法调用语句数为256,说明项目中的方法之间存在较多的交互,需要注意方法调用的合理性和效率。
2、 家居强电电路模拟程序-4
根据题目的要求编写程序来完成 家居强电电路模拟程序-4Device 类是所有设备类的基类,提供了设备的基本属性和方法。其他设备类通过继承 Device 类,可以重用这些通用属性和方法,并根据具体的设备需求进行扩展和定制。
GND 类继承自 Device,表示接地设备,并重写了 getVoltage() 方法,使得电压固定为 0。
SeriesCircuit 和 ParallelCircuit 是两种电路类型,分别代表串联电路和并联电路。SeriesCircuit 可以包含多个 Device 对象,而 ParallelCircuit 可以包含多个 SeriesCircuit 对象。
Diode 是一个特殊的设备类,表示二极管,具有正向导通和反向截止两种状态,并根据引脚电压动态更新其状态。
MutexSwitch 是一种特殊的开关设备,能够控制多个分支电路的通断。它通过 connectedDevices 属性与 Device 类进行关联。
Switch、FourSpeed 和 ContinuousSpeed 类是控制设备,用于控制其他设备的开关状态或速度,它们也通过 connectedDevices 属性与 Device 类关联。
Bulb、FluorescentTube、Fan、FloorFan 和 Curtain 类是受控设备,它们的状态会根据控制设备的状态进行更新。这些设备类继承自 Device 类,并重写了 deviceSpecificUpdate() 方法来实现状态更新。
SmartHomeSimulator 是智能家居模拟器类,负责管理和控制所有设备和电路。它通过 devices 属性与 Device 类关联,并提供了添加设备、获取设备、添加连接、控制设备和模拟等方法来模拟智能家居系统。
新增功能说明:
管脚电压显示:在每个电器输出状态信息后,依次输出该电器每个管脚的电压。
电流限制:为了防止电器过热和烧坏电路,每个元器件都有最大电流的设置。当实际电流超过最大电流时,系统将在该电器输出信息的最后加上提示 "exceeding current limit error",并用英文空格与前面的信息分隔开。
短路检测:如果电路出现无穷大的电流(如短路),则不会输出各个元器件的信息,而只输出提示 "short circuit error"。
并联电路嵌套支持:本次迭代考虑了并联电路中包含并联电路的情况,即串联电路可以作为并联电路的一部分,形成更复杂的电路结构。
二极管元件:新增了二极管元件,它的电路特性为:在正向电压下导通,反向电压下截止。
代码示例和操作说明:
1. 调速器控制:
通过 Math.min() 和 Math.max() 方法,确保分档调速器的速度值始终在 0 到 3 的范围内:
java
speedLevel = Math.min(3, speedLevel + 1);
speedLevel = Math.max(0, speedLevel - 1);
这些方法分别返回两个数中的最小值或最大值,确保 speedLevel 不会超出预定范围。这样控制具有有限状态的变量(如速度、音量等)更加健壮。
2. 显式类型转换:
当列表存储 Device 类型及其子类的对象时,如果需要访问子类特有的方法或属性,就需要显式地进行类型转换。以下是一个示例:
java
List<Device> connectedDevices = new ArrayList<>(); // 设备列表
Fan fan = (Fan) connectedDevices; // 强制类型转换
在这个例子中,connectedDevices 是一个存储 Device 类型对象的列表,尽管其中可能存储的是 Fan 类型的对象。为了访问 Fan 类中独有的方法和属性,我们需要将 Device 类型的对象转换为 Fan 类型。
复杂性和挑战:
计算复杂性增加:新增的管脚电压显示、电流限制、短路检测等功能,要求在电路计算过程中进行更多的计算和判断,这无疑增加了计算的复杂性。
电路分析难度提高:由于并联电路中可以嵌套其它并联电路,同时引入了二极管元件,这使得电路的结构和分析更加复杂,需要对电路的工作原理和特性有更深入的理解。
数据处理和输出要求更高:在输出结果时,需要包含更多的细节信息,如管脚电压和电流限制提示等,这要求在数据处理和输出时更加精确和细致,增加了输出处理的难度。
通过这些增强的功能和复杂性的引入,智能家居模拟系统的设计和实现更加完备,但也相应地提高了系统的计算复杂性和电路分析的挑战。
该题目的类图:
抽象类 Device
作用:Device 是所有电路设备的父类,定义了共享的属性和方法。作为一个抽象类,它不能直接实例化。
数据成员:
String name:设备名称。
double resistance:电阻值。
double current:电流。
double electricity:电量。
double potential:设备电压。
double potential1 和 double potential2:设备两端引脚的电压。
String pin1 和 String pin2:设备的两个引脚名称。
int location:设备在电路中的位置。
boolean decide:辅助标志位,用于标记设备的特定状态。
方法成员:
构造方法:
Device():默认构造方法。
Device(String name, String pin1, String pin2):带参数的构造方法,用于初始化设备名称和引脚。
String getName():返回设备的名称。
类关系:Device 被其他设备类继承。
抽象类 ControlDevice
作用:ControlDevice 是所有控制类设备的基类,派生出具体的控制设备,如开关、调速器等。
数据成员:
继承自 Device,无新增成员。
方法成员:
构造方法:
ControlDevice():默认构造方法。
ControlDevice(String name, String pin1, String pin2):带参数的构造方法,用于初始化名称和引脚。
抽象方法:
void setState(String num):设置设备状态的方法。
类关系:ControlDevice 继承自 Device,并被具体的控制设备(如 Switch, BinningGovernor 等)继承。
类 Switch
作用:表示一个开关设备,通过 state 属性控制电路的开关状态。
数据成员:
boolean state:开关的开/关状态。
方法成员:
构造方法:
Switch():默认构造方法。
Switch(String name, String pin1, String pin2):初始化开关名称和引脚。
boolean isState():返回当前开关状态。
String getState():返回状态描述字符串(例如:"closed" 或 "turned on")。
void setState(String num):切换开关状态。
String toString():返回开关的状态、电压和电流信息。
类关系:继承自 ControlDevice。
类 MutexSwitches
作用:表示互斥开关,用于控制多个电路的互斥逻辑。
数据成员:
boolean state:互斥开关的状态。
String pin3:第三引脚名称。
double potential3:第三引脚的电势。
double electricity1:通过第三引脚的电流。
方法成员:
构造方法:
MutexSwitches():默认构造方法。
MutexSwitches(String name, String pin1, String pin2):初始化互斥开关名称和引脚。
boolean isState():返回当前状态。
String getState():返回状态描述字符串。
void setState(String num):切换开关状态。
String toString():返回互斥开关的状态及相关电气信息。
类关系:继承自 ControlDevice。
类 BinningGovernor
作用:表示分档调速器,可以通过档位来调节输出电压。
数据成员:
int gears:当前档位。
double voltage:输出电压。
方法成员:
构造方法:
BinningGovernor():默认构造方法。
BinningGovernor(String name, String pin1, String pin2):初始化调速器名称和引脚。
double getOutputVoltage(double num):根据档位和输入电压计算输出电压。
void setVoltage(int voltage):设置输出电压。
int getGears():获取当前档位。
void setGears(int gears):设置档位。
void setState(String num):根据输入调整档位。
String toString():返回档位状态及相关信息。
类关系:继承自 ControlDevice。
类 ContinuousGovernor
作用:表示连续调速器,支持精细调整输出电压。
数据成员:
double gears:当前档位。
double voltage:输出电压。
方法成员:
构造方法:
ContinuousGovernor():默认构造方法。
ContinuousGovernor(String name, String pin1, String pin2):初始化调速器名称和引脚。
double getOutputVoltage(double num):根据档位和输入电压计算输出电压。
void setGears(double gears):设置档位。
double getGears():获取当前档位。
void setState(String num):设置档位。
String toString():返回调速器的状态及相关信息。
类关系:继承自 ControlDevice。
抽象类 ControlledDevice
作用:ControlledDevice 是所有受控设备的基类,派生出具体的受控设备,如灯具、电风扇等。
数据成员:
继承自 Device,无新增成员。
方法成员:
构造方法:
ControlledDevice():默认构造方法。
ControlledDevice(String name, String pin1, String pin2):初始化名称和引脚。
抽象方法:
void setPotential():设置设备的电势。
类关系:继承自 Device,并被具体的受控设备(如 Incandescent, Fluorescent 等)继承。
类 Incandescent
作用:表示白炽灯,根据电压来计算亮度。
数据成员:
double brightness:灯的亮度。
方法成员:
构造方法:
Incandescent():默认构造方法。
Incandescent(String name, String pin1, String pin2):初始化灯具名称和引脚。
double getBrightness():获取亮度。
void setBrightness(double brightness):设置亮度。
void setPotential():根据电压计算亮度。
String toString():返回灯具的状态及相关信息。
类关系:继承自 ControlledDevice。
类 Fluorescent
作用:表示日光灯,根据电压计算亮度。
数据成员:
double brightness:灯的亮度。
方法成员:
构造方法:
Fluorescent():默认构造方法。
Fluorescent(String name, String pin1, String pin2):初始化灯具名称和引脚。
double getBrightness():获取亮度。
void setBrightness(int brightness):设置亮度。
void setPotential():根据电压计算亮度。
String toString():返回灯具的状态及相关信息。
类关系:继承自 ControlledDevice。
类 CeilingFan
作用:表示吊扇,根据电压计算风扇的速度。
数据成员:
int speed:风扇速度。
方法成员:
构造方法:
CeilingFan():默认构造方法。
CeilingFan(String name, String pin1, String pin2):初始化风扇名称和引脚。
int getSpeed():获取风扇速度。
void setPotential():根据电压计算风扇速度。
String toString():返回风扇的状态及相关信息。
类关系:继承自 ControlledDevice。
类 Floorfan
作用:表示落地扇,与吊扇类似,根据电压计算风扇速度。
数据成员:
int speed:风扇速度。
方法成员:
与 CeilingFan 类相同。
类关系:继承自 ControlledDevice。
类 ControlledCurtains
作用:表示智能窗帘,控制窗帘的开合比例。
数据成员:
String proportion:窗帘的开合比例。
double brightness:窗帘的亮度。
方法成员:
构造方法:
ControlledCurtains():默认构造方法。
ControlledCurtains(String name, String pin1, String pin2):初始化窗帘名称
以及除了这七个类之外的Main之中的部分代码
根据对应的字母在模拟电路中加入相对应的类
// 伪代码示例 public class Main { public static void main(String[] args) { List<Circuit> circuits = new ArrayList<>(); // 读取输入并构建电路 while (true) { String line = readInput(); if (line.equals("end")) break; if (line.startsWith("#T")) { // 处理串联电路 SeriesCircuit seriesCircuit = new SeriesCircuit(); seriesCircuit.parseAndAddConnection(line); circuits.add(seriesCircuit); } else if (line.startsWith("#M")) { // 处理并联电路 ParallelCircuit parallelCircuit = new ParallelCircuit(); parallelCircuit.parseAndAddConnection(line); circuits.add(parallelCircuit); } else { // 处理控制命令 processControlCommand(line); } } // 模拟电路并输出结果 simulateCircuits(circuits); } private static void simulateCircuits(List<Circuit> circuits) { // 遍历所有电路,计算每个设备的状态 for (Circuit circuit : circuits) { circuit.simulate(); } // 输出所有设备的状态 printDeviceStates(); } }
SourceMonitor分析如下:
复杂度分析
整个项目中,Main.main()方法的复杂度最高,达到了37,语句数也较多,有93个语句,这可能是一个需要重点关注和优化的方法。
平均复杂度为3.85,说明整体代码的复杂度处于中等水平,但有一些方法的复杂度较高,可能会影响代码的可读性和维护性。代码规模代码行数达到1,100行,语句数为627,这表明项目有一定的规模。注释情况带注释的代码行百分比为13.3,说明代码中的注释相对较少,可能需要增加注释来提高代码的可读性。方法调用方法调用语句数为256,说明项目中的方法之间存在较多的交互,需要注意方法调用的合理性和效率。
三、踩坑心得
家居强电电路模拟程序3
原始代码直接使用分压公式来计算设备电压,而没有考虑电路可能因某些设备(如开关、调速器等)断开而导致电路不通的情况。这种做法在实际电路断路的情况下是不可行的,因为断路后的电压应该为零,而非依照分压公式计算。
原始代码存在问题:
java
for (Device device : devices) {
device.voltage = (device.resistance / totalResistance) * totalVoltage;
if (voltage > 0) {
device.deviceSpecificUpdate();
}
}
这段代码简单地根据分压公式计算每个设备的电压,但没有考虑电路的断路问题。假如电路中某个开关或调速器断开,按原逻辑仍会计算每个设备的电压,这在实际情况下是不合理的。因为一旦电路断开,所有设备的电压应为 0。
问题分析:
在电路断开(如开关断开)时,应该立即停止电压分配,确保所有设备的电压为零。
在复杂电路中,不同设备之间的连接方式(串联、并联)会影响电压的传播,未考虑断路时电压如何影响各个部分。
改正后的代码:
改正后的代码首先检查电路是否断开,然后根据电路的状态来决定如何计算或设置设备电压。
java
// 检查电路是否因开关或调速器断开
for (Device device : devices) {
if (device instanceof Switch && ((Switch) device).getState() == 0) {
circuitOpen = true; // 如果某个开关断开,标记电路为断开
break;
}
// 对其他类型设备的检查
if (device instanceof ContinuousSpeed && ((ContinuousSpeed) device).getSpeedLevel() == 0) {
circuitOpen = true; // 如果调速器断开,标记电路为断开
break;
}
}
// 根据电路状态设置设备电压
for (Device device : devices) {
if (circuitOpen) {
device.voltage = 0; // 电路断开时,将所有设备电压设置为 0
// 对于并联电路中的串联电路,确保电压传播为 0
if (device instanceof ParallelCircuit) {
List<SeriesCircuit> seriesCircuits = ((ParallelCircuit) device).seriesCircuits;
for (SeriesCircuit seriesCircuit : seriesCircuits) {
seriesCircuit.voltage = 0;
seriesCircuit.propagateVoltage(0); // 确保所有串联电路的电压都为 0
}
}
} else {
// 计算电压分配(电路未断开)
device.voltage = (device.resistance / totalResistance) * totalVoltage;
}
device.deviceSpecificUpdate(); // 更新设备状态
}
代码改进说明:
断路检测: 首先,通过循环检查电路中是否存在开关或调速器断开(例如开关的状态为 0,调速器的速度等级为 0)。如果检测到任何设备处于断开状态,circuitOpen 标志会被设置为 true,表示电路已断开。
电压设置: 在电路断开时,通过 circuitOpen 标志来判断是否需要将所有设备的电压设置为 0。如果电路断开,所有设备的电压会被清空,并且对于并联电路中的串联部分,电压也会被传播为 0,确保电压变更正确地传递。
并联电路处理: 对于 ParallelCircuit 类型的设备,在电路断开时,还会遍历其内部的串联电路(SeriesCircuit),将它们的电压也设置为 0,并通过 propagateVoltage(0) 方法将电压变化传播到相关设备。
优势:
正确的电压分配: 断路时,所有设备的电压都设置为 0,避免了错误的电压计算。
支持复杂电路结构: 对并联和串联电路的设备处理进行了细化,确保电路状态的变化能够正确传播到所有相关设备。
健壮性: 通过对设备状态(如开关和调速器)的检测,使得代码能够在各种电路状态下正确工作。
这样修改后的代码更加符合电路实际运行的逻辑,能够处理电路断开的情况,并且在复杂的电路结构中能够正确地分配电压。
家居强电电路模拟程序4
原代码中使用了一个单一的 branchOpen 变量来判断电路是否断开。该方法在处理互斥开关和普通开关共同作用的电路时会出现判断错误,可能错误地认为整个串联电路已断开,即使其他设备或开关处于闭合状态。此外,原代码没有考虑电路的复杂性,特别是互斥开关(如 MutexSwitch)等设备对电路状态的影响。
原代码的断路判断逻辑过于简单,仅依据一个 Switch 类型的设备的状态来决定是否断开电路,而忽略了多个开关的交互作用,尤其是在互斥开关的情况下。并且,原代码将断开电路的所有设备电压直接设为 0 或 vv,这种简单的二分法无法准确地反映电路的真实情况。
改进后的代码
改进后的代码引入了 seriesCircuitOpenStatus 列表,记录每个串联电路的断开状态,并综合考虑了 Switch 和 MutexSwitch 等设备的状态。对于每个串联电路,首先检查所有开关的状态(包括普通的 Switch 和 MutexSwitch)。如果电路断开,标记该串联电路为关闭状态;如果电路没有断开,则计算电压并传播。
java
if (device instanceof ParallelCircuit) {
List<SeriesCircuit> seriesCircuits = ((ParallelCircuit) device).seriesCircuits;
List<Boolean> seriesCircuitOpenStatus = new ArrayList<>();
// 检查每个串联电路的开关状态
for (SeriesCircuit seriesCircuit : seriesCircuits) {
boolean isOpen = false;
// 检查串联电路中每个设备的状态
for (Device device1 : seriesCircuit.devices) {
if (device1 instanceof Switch && ((Switch) device1).getState() == 0) {
isOpen = true; // 如果发现关闭的开关,标记为断开
break;
} else if (device1 instanceof MutexSwitch) {
// 检查互斥开关状态
MutexSwitch mutexSwitch = (MutexSwitch) device1;
if ((mutexSwitch.pin.equals("2") && !mutexSwitch.getState2()) ||
(mutexSwitch.pin.equals("3") && !mutexSwitch.getState3())) {
isOpen = true; // 如果互斥开关的状态导致断开,标记为断开
break;
}
}
}
// 将当前串联电路的状态记录到列表
seriesCircuitOpenStatus.add(isOpen);
}
// 根据串联电路的断开状态计算电压
for (int i = 0; i < seriesCircuits.size(); i++) {
SeriesCircuit seriesCircuit = seriesCircuits.get(i);
if (!seriesCircuitOpenStatus.get(i)) {
// 如果串联电路未断开,根据总电阻和设备的电阻计算电压
double seriesResistance = seriesCircuit.getTotalResistance();
for (Device device1 : seriesCircuit.devices) {
device1.voltage = device1.CalculateResistance() / seriesResistance * vv;
// 将计算出的电压传播到设备
if (!device1.id.equals("H")) {
seriesCircuit.propagateVoltage(device1.voltage);
}
}
} else {
// 如果串联电路断开,将电压设置为 0
seriesCircuit.voltage = 0;
}
}
}
改进分析
引入 seriesCircuitOpenStatus 列表:
使用 seriesCircuitOpenStatus 列表来存储每个串联电路的开关状态(打开或关闭)。通过这种方式,代码可以针对每个串联电路独立判断是否断开,而不是一旦发现断开的开关就简单地将整个电路电压设为 0。
考虑多个开关类型:
除了常规的 Switch 设备,代码还考虑了 MutexSwitch 类型的设备,尤其是它们的互斥状态(例如 pin = "2" 或 pin = "3" 时的状态)。这使得电路在复杂开关状态下能够做出更准确的断开判断。
电压计算更精确:
对于未断开的串联电路,使用电路的总电阻和每个设备的电阻计算每个设备的电压,而不是简单地将电压设置为 0 或 vv。这符合电压分配的物理原理,能更准确地模拟实际电路行为。
电压传播:
对于闭合的串联电路,计算出的电压会被传播到电路中的设备上。通过 seriesCircuit.propagateVoltage(device1.voltage) 方法,确保电压的传播符合实际电路的工作原理。
优势
更精确的断路判断:通过独立判断每个串联电路的状态,避免了错误地将整个电路断开。
考虑互斥开关:代码能够正确处理 MutexSwitch 类型设备的影响,确保电路在复杂开关状态下的正确行为。
合理的电压分配:电压计算不再仅限于简单的 0 或 vv,而是基于每个设备的电阻和电路的总电阻进行精确计算。
电压传播更符合物理原理:通过电压传播方法,确保电压分配到每个设备时是合理的。
这个改进方案能够更好地处理复杂电路中的各种设备和开关状态,使电路的行为更加符合实际物理原理,避免了原代码中的错误。
四、改进建议
1. 答题判题程序 - 改进建议
方法过长问题
当前多个类中的方法过长且逻辑复杂,例如 SeriesCircuit 类中的 deviceSpecificUpdate 方法和 SmartHomeSimulator 类中的 simulate 方法。长方法增加了代码的可读性和维护难度,因此不利于理解和扩展。建议将这些方法中相对独立的逻辑模块提取到私有方法中,确保每个方法都只承担单一的责任。比如在 SeriesCircuit 类中的 deviceSpecificUpdate 方法中,涉及到电路断开检测、互斥开关影响的设备电阻更新以及根据设备类型更新电压等逻辑,可以将这些步骤分别提取为单独的私有方法,从而让主方法更加简洁易懂。
类职责划分问题
部分类的职责过于冗杂,例如 SmartHomeSimulator 类承担了设备管理、连接管理、控制操作和模拟运行等多重功能,导致类的规模庞大且复杂。建议对这些职责进行拆分,将设备连接操作提取到单独的类中,或将设备状态更新等职责下放到具体设备类中,从而让每个类的功能更加专一,符合单一职责原则,提升代码的可维护性和扩展性。
重复代码处理
在多个地方,尤其是在设备状态改变时(如开关、调速器等操作),会有类似的代码逻辑,比如更新连接设备的电压和状态。为了减少代码冗余,可以将这些重复的逻辑提取成一个公共方法,并在各个需要的地方进行调用。这不仅能够减少代码重复,还能提高代码的复用性,便于后续的维护和修改。
2. 家居强电电路模拟程序 - 改进建议
输入验证与异常处理不足
目前在用户输入解析、设备创建、连接建立及控制指令处理过程中,输入验证相对简单,缺乏足够的异常处理机制。比如,当用户输入不符合格式要求时(如 Integer.parseInt 抛出 NumberFormatException),可能导致程序错误甚至崩溃。建议增强输入验证逻辑,使用 try-catch 块捕获可能的异常,并提供友好的错误提示,帮助用户正确输入,从而提升程序的健壮性和容错能力。
设备类型扩展考虑
随着智能家居系统的发展,未来可能需要添加新的设备类型。目前的代码结构在添加新设备时,需在多个地方进行修改(如在 main 方法中添加设备创建逻辑,在 SmartHomeSimulator 类的 control 方法中增加新设备的控制操作)。为优化扩展性,可以采用设计模式(如工厂模式)来集中管理设备对象的创建。通过工厂模式,只需在工厂类中修改设备创建逻辑,避免修改代码中的多个部分,从而提高代码的可扩展性和可维护性。
避免不必要的计算和遍历
在某些方法中,存在重复计算或不必要的遍历操作,例如在计算电路总电阻、更新设备电压时,可能会多次遍历相同的设备列表或重复计算相同的值。建议通过缓存中间计算结果(如电路的总电阻)来避免重复计算,或者优化遍历逻辑,减少冗余操作。这不仅能提高程序的运行效率,还能在处理复杂或大规模电路时,显著改善性能表现。
五、总结
通过三次题目集的实践,我掌握了如何将复杂的系统拆解成多个独立的类,并合理地分配每个类的职责。例如,在本次题目中,我将电路中的设备划分为 Device、ControlDevice 和 ControlledDevice 等抽象基类,并通过具体的子类来实现不同的功能。这一过程中,我深刻理解了继承的意义,特别是抽象类和接口的应用,使得通用逻辑的实现变得更加简洁。比如,通过设计 ControlDevice 和 ControlledDevice 类,能够通过多态统一管理同类设备。同时,我也更加意识到封装的重要性,通过限制对数据成员的直接访问,保障了系统的安全性和稳定性。在本阶段的作业中,我学会了根据具体问题选择合适的数据结构。例如,在处理设备关系时,我使用了 Map 来存储串联和并联设备的关系,从而提高了设备的检索与管理效率。在电阻、电流和电压计算等问题中,我利用递归和迭代的方法设计了逻辑清晰且高效的算法,这种递归思路对解决树形或图形结构问题特别有帮助。在处理控制设备(如开关、调速器)与受控设备(如灯、风扇)的逻辑时,我借鉴了类似策略模式的设计思想,将不同的设备操作逻辑独立封装了起来。此外,通过设备状态的变化引发电路状态的更新,我初步接触到事件驱动设计的思路,虽然没有完全实现,但为我提供了很好的思考方向。我还逐步理解了命名规范、类的职责分离和注释的重要性。例如,代码中通过方法命名(如 setPotential、getOutputVoltage)清晰地表达了功能,增强了代码的可读性。在面对复杂的电路问题时,我逐渐意识到人工验证的困难,并开始认识到单元测试和集成测试对验证系统行为的必要性。在实践过程中,我发现多个类中存在重复逻辑,导致代码冗长且修改时容易遗漏;过长的方法(如 control 和 output 方法)使得代码难以理解和维护。目前,我的代码大多通过手动输入来测试逻辑,但还没有建立完善的单元测试体系。为了解决这些问题,我计划引入工具类或抽象方法,将重复代码提取为通用模块;使用面向对象设计模式优化代码结构,减少耦合;同时,为复杂功能编写单元测试,确保逻辑的正确性。经过这一阶段的学习,我对面向对象编程的核心思想有了更加深入的理解,并在分解和实现复杂问题方面得到了大量锻炼。这些经验将在未来的学习和开发中发挥重要作用。我对类与类之间的关系设计有了更清晰的认识,能够合理运用继承、多态和封装来简化复杂系统。在解决递归计算和设备状态处理等问题时,我的算法设计和实现能力得到了提升。逐渐从单一功能的实现转向考虑代码的复用性、扩展性和维护性。通过不断的作业实践,我认识到代码质量的重要性,并能主动优化已有的逻辑。
六、学期总结
本学期的收获与心得
在本学期的Java学习和PTA练习过程中,通过多次参与题目集和实践活动,我获得了丰富的经验和深刻的体会。在专业知识方面,我对面向对象编程的理解有了显著深化。通过设计设备类和电路类,我深入了解了继承、多态和封装等面向对象特性的实际应用。例如,通过子类继承父类并重写方法来实现多态,增强了代码的可扩展性和复用性。而将属性和方法封装在类内部,不仅提高了代码的清晰度,也便于后续维护。此外,我还掌握了如何处理复杂系统中的设备连接问题,学会了运用组合与聚合关系来构建层次分明且具有交互性的系统模型,这在面向对象设计中是一项重要的技能在完成多个题目集的过程中,我遇到了不少挑战,特别是在编写家居强电电路模拟程序时。初期在电压计算时,我未能考虑到电路并联时的电阻变化,也忽视了设备状态对电路连接的影响。经过反复调试,我学会了如何处理并联支路和开关控制支路的电路问题,掌握了等效电阻计算的正确方法,从而能够准确地进行分压计算。此外,题目中的输出排序问题也让我积累了更多实践经验,每一个细节的调整都让我更具备了思考问题的深度和解决问题的能力面对代码中的复杂性和性能瓶颈,我逐渐学会从更高层次分析和优化代码结构。我开始注重方法的职责划分、类的设计、以及代码的可扩展性等方面,培养了从全局视角思考问题的习惯,学会了如何提高代码的效率与可维护性。特别是在考虑未来可能的功能扩展时,我有意识地探索如何使用设计模式(如工厂模式)来优化代码结构,以便后续的功能添加和维护。通过与同学们的交流,我深刻体会到讨论和反馈的重要性。许多困扰我的问题,在与同学的讨论中能获得新的启发,帮助我找到解决问题的思路。因此,我期望今后能有更多与同学们分享经验的机会,互相学习,拓展思维边界。同时,我也希望教师能够建立更明确的作业反馈机制,指出我们的不足,并提供具体的改进建议,以帮助我们更加有效地提升本学期的学习充满了挑战,也充满了收获。这些收获不仅体现在专业知识和技能的提高上,还在于我思维方式的转变和解决问题能力的增强。所有的积累为我未来的学习和实践奠定了坚实的基础,帮助我在今后的学习中更好地应对复杂问题,提升综合能力。最后我想说的是,真的好难写啊
标签:总结性,题目,String,构造方法,double,Blog,电路,电压,设备 From: https://www.cnblogs.com/bangksm/p/18637893