BLOG-3
第七次大作业
家居强电电路模拟程序-3
题目分析
题目要求设计一个智能家居强电电路模拟系统,涉及到多种控制设备和受控设备,并且需要处理串联和并联电路的连接关系。
更新了电路

本次相较于上次新增了互斥开关
互斥开关有3个引脚:1个是汇总引脚,另两个是分支引脚。
开关电路示意图如图1所示,左边是汇总引脚,编号为1;右边两个是分支引脚,右上的输出引脚为2,右下输出引脚为3。图中1、2、3引脚均可以是输入引脚,当1为输入引脚时,2、3引脚为输出引脚;1为输出引脚时,2、3引脚为输入引脚。
互斥开关只有两种状态:开关接往上面的2号引脚、接往下面的3号引脚。开关每次只能接通其中一个分支引脚,而另一个分支引脚处于断开状态。
互斥开关的默认状态为1、2引脚接通,1、3引脚断开。
图1中所示的互斥开关可以反过来接入电路,即汇总引脚接往接地端,两个分支引脚接往电源端。

本次迭代模拟一种受控窗帘:
受控窗帘的电路符号为S,其最低工作电压为50V,电压达到或超过50V,窗帘即可正常工作,不考虑室外光照强度和室内空间大小等因素,窗帘受室内灯光的光照强度控制。
当电路中所有灯光的光照强度总和在[0,50)lux范围内,窗帘全开;
在[50,100)lux范围内,窗帘打开比例为0.8;
在[100,200)lux范围内,窗帘打开比例为0.6;
在[200,300)lux范围内,窗帘打开比例为0.4;
在[300,400)lux范围内,窗帘打开比例为0.2;
在400lux及以上范围内,窗帘关闭。
当电压低于50V,窗帘不工作,默认为全开状态。
如果电路中没有灯或者灯全部关闭,光照强度为0,窗帘处于全开状态。
受控设备电阻:白炽灯的电阻为 10,日光灯的电阻为 5,吊扇的电阻为 20,落地扇的电阻为 20,窗帘电阻为15。
具体设计
设计思路延续上次大作业的构想,还是这几个大类的划分
电路设备类:描述所有电路设备的公共特征,如引脚、电阻等。
受控设备类、控制设备类:分别对应受控设备和控制设备,实现各自的功能和状态管理。
串联电路类:模拟一条由多个电路设备构成的串联电路。
并联电路类:继承电路设备类,模拟并联电路的连接和计算。
实现步骤
解析输入信息:读取并解析设备信息、连接信息、控制设备调节信息、电源接地标识、串联电路信息和并联电路信息。
构建电路模型:根据解析的输入信息,构建电路模型,包括设备对象、连接关系、串联和并联电路。
计算电路状态:根据设备的当前状态和连接关系,计算每个设备的电压、电流、亮度、转速等参数。
输出结果:按照指定的格式输出所有设备的状态或参数。
下面是我对于类的设计思路以及给出了主函数Main类的代码实现:
Equipment抽象类
作为所有具体设备类的基类,定义了设备的一些通用属性(如title用于标识设备名称、voltage表示电压、current表示电流)以及必须由子类实现的抽象方法(getTitle用于获取设备标题、showDetails用于展示设备详细信息、turnOff用于关闭设备功能)。通过这种抽象设计,为不同类型的具体设备类提供了统一的接口规范,使得代码在处理各种设备时具有一致性和可扩展性。
CircuitSwitch类
继承关系:继承自Equipment抽象类,并实现了Comparable接口。
作用:用于模拟电路中的开关设备。它包含一个私有属性mode来表示开关的状态(0 表示打开,1 表示闭合)。通过构造函数和setMode方法来初始化和更新开关状态,并根据状态计算电流值(打开时电流为 0,闭合时电流等于输入电压)。重写了getTitle、showDetails和turnOff等抽象方法,分别用于获取设备标题、按照规定格式(如@设备标识:turned on或@设备标识:closed)展示开关状态以及将开关设置为打开状态(即关闭设备功能)。实现Comparable接口使得可以对开关对象进行比较,比较依据是设备标题。
GearGovernor类
继承关系:继承自Equipment抽象类。
作用:用于模拟分档调速器设备。
它有一个私有属性gearSetting表示当前的档位设置。在构造函数中,根据传入的档位值通过setCurrentBasedOnGears方法计算并设置相应的电流值(不同档位对应不同比例的输入电压作为电流)。重写了getTitle、showDetails和turnOff等抽象方法,其中showDetails方法用于按照@设备标识:档位值的格式展示当前档位信息,turnOff方法可用于实现关闭设备的相关逻辑
ContinuousGovernor类
-用于模拟连续调速器设备。它包含一个私有属性ratio表示档位比例。在构造函数中,根据传入的比例值计算电流值(电流等于输入电压乘以档位比例)。重写了getTitle、showDetails和turnOff等抽象方法,showDetails方法用于按照@设备标识:保留两位小数的档位比例值的格式展示当前档位信息,turnOff方法可用于添加关闭设备的相关功能。
IncandescentLight类
-用于模拟白炽灯设备。它有一个私有属性brightness用于存储灯泡的亮度值。在构造函数中,根据传入的电压值通过calculateBrightness方法计算灯泡的亮度(根据不同的电压范围采用不同的计算公式)。重写了getTitle、showDetails和turnOff等抽象方法,showDetails方法用于按照@设备标识:亮度值的格式展示灯泡的亮度,turnOff方法用于将灯泡亮度设置为 0,即关闭灯泡。
SolarLight类
-用于模拟日光灯设备。它包含一个私有属性brightness用于存储日光灯的亮度值。在构造函数中,根据传入的电压值简单判断并设置亮度值(电压不为 0 时亮度为 180,否则为 0)。重写了getTitle、showDetails和turnOff等抽象方法,showDetails方法用于按照@设备标识:亮度值的格式展示日光灯的亮度,turnOff方法用于将日光灯亮度设置为 0,即关闭日光灯。
FanDevice类
-用于模拟风扇设备。它有一个私有属性speed用于存储风扇的转速值。在构造函数中,根据传入的电压值通过calculateSpeed方法计算风扇的转速(根据不同的电压范围采用不同的计算公式)。重写了getTitle、showDetails和turnOff等抽象方法,showDetails方法用于按照@设备标识:转速值的格式展示风扇的转速,turnOff方法用于将风扇转速设置为 0,即关闭风扇。
EquipmentCollection类
-用于管理一系列的设备对象。它内部维护一个List类型的成员变量devices,通过addDevice方法可以向其中添加各种类型的设备对象,getDevices方法用于获取存储的设备列表,displayAll方法用于遍历设备列表并调用每个设备的showDetails方法,从而实现统一展示所有设备的状态或参数信息的功能。
Curtain 类
-Curtain 类用于模拟受控窗帘的行为,其电路符号为 S,最低工作电压为 50V。窗帘的打开比例根据室内灯光的光照强度总和进行调整:光照强度在 [0,50) lux 时窗帘全开,[50,100) lux 时打开 80%,[100,200) lux 时打开 60%,[200,300) lux 时打开 40%,[300,400) lux 时打开 20%,400 lux 及以上时窗帘关闭。若电压低于 50V,窗帘默认全开;若无灯光或灯光全部关闭,光照强度为 0,窗帘也全开。类中包含私有属性 openPercentage(窗帘打开比例)、voltage(工作电压)和 totalLux(光照强度总和),并提供设置电压、光照强度、计算打开比例、展示状态和关闭窗帘的方法。
Main类
-创建了一些必要的数据结构,如Scanner用于读取用户输入,Map<String, Integer>用于跟踪开关状态变化次数,多个List用于存储连接信息、控制命令等。
通过循环读取用户输入,根据输入内容是否包含[或 ``#将其分别添加到对应的connections或commands列表中,直到读取到end` 为止。
对控制命令列表commands进行解析,针对不同类型的控制命令(开关、分档调速器、连续调速器)进行相应的处理,如更新开关状态跟踪信息、调整分档调速器的档位、设置连续调速器的档位比例等。
遍历连接信息列表connections,通过正则表达式匹配解析出连接的设备信息,根据设备类型创建相应的设备对象并添加到equipmentCollection中,在创建设备对象时,会根据前一个设备的输出电流作为当前设备的输入电压来构建电路连接关系。
最后调用equipmentCollection的displayAll方法,展示所有设备的状态或参数信息。
点击查看代码
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Map<String, Integer> switchTracker = new HashMap<>();
List<CircuitSwitch> switches = new ArrayList<>();
EquipmentCollection equipmentCollection = new EquipmentCollection();
List<String> connections = new ArrayList<>();
List<String> commands = new ArrayList<>();
while (true) {
String line = scanner.nextLine();
if (line.equals("end")) break;
if (line.contains("[")) connections.add(line);
else if (line.contains("#")) commands.add(line);
}
int governorSettings = 0;
double continuousRatio = 0;
if (!commands.isEmpty()) {
for (String command : commands) {
if (command.startsWith("#K")) {
Matcher matcher = Pattern.compile("#(K[0-9]+)").matcher(command);
while (matcher.find()) {
String switchName = matcher.group(1);
switchTracker.put(switchName, switchTracker.getOrDefault(switchName, 0) + 1);
}
} else if (command.startsWith("#F")) {
if (command.contains("+") && governorSettings < 3) governorSettings++;
if (command.contains("-") && governorSettings > 0) governorSettings--;
} else if (command.startsWith("#L")) {
Matcher matcher = Pattern.compile("#L[0-9]+:([0-9.]+)").matcher(command);
if (matcher.find()) {
continuousRatio = Double.parseDouble(matcher.group(1));
}
}
}
}
for (String connection : connections) {
Matcher matcher = Pattern.compile("\\[VCC ([A-Z0-9]+)\\-1\\]").matcher(connection);
if (matcher.find()) {
String name = matcher.group(1);
switchOrDevice(name, switchTracker, governorSettings, continuousRatio, equipmentCollection);
continue;
}
matcher = Pattern.compile("\\[[A-Z0-9]+\\-2 ([A-Z0-9]+)\\-1\\]").matcher(connection);
if (matcher.find()) {
String name = matcher.group(1);
String deviceType = name.substring(0, 1);
if (deviceType.equals("K")) {
CircuitSwitch newSwitch = createSwitch(name, equipmentCollection);
equipmentCollection.addDevice(newSwitch);
} else {
Equipment lastDevice = equipmentCollection.getDevices().get(equipmentCollection.getDevices().size() - 1);
switch (deviceType) {
case "D":
equipmentCollection.addDevice(new FanDevice(lastDevice.getCurrent(), name));
break;
case "B":
equipmentCollection.addDevice(new IncandescentLight(lastDevice.getCurrent(), name));
break;
case "R":
equipmentCollection.addDevice(new SolarLight(lastDevice.getCurrent(), name));
break;
}
}
}
if (connection.contains("GND")) break;
}
equipmentCollection.displayAll();
}
private static void switchOrDevice(String name, Map<String, Integer> switchTracker, int governorSettings, double continuousRatio, EquipmentCollection collection) {
if (name.contains("K")) {
int switchCount = switchTracker.getOrDefault(name, 0);
CircuitSwitch newSwitch = new CircuitSwitch(220, switchCount, name);
collection.addDevice(newSwitch);
} else if (name.contains("F")) {
collection.addDevice(new GearGovernor(220, governorSettings, name));
} else if (name.contains("L")) {
collection.addDevice(new ContinuousGovernor(220, continuousRatio, name));
} else if (name.contains("D")) {
collection.addDevice(new FanDevice(220, name));
} else if (name.contains("B")) {
collection.addDevice(new IncandescentLight(220, name));
} else if (name.contains("R")) {
collection.addDevice(new SolarLight(220, name));
}
}
private static CircuitSwitch createSwitch(String name, EquipmentCollection collection) {
return new CircuitSwitch(220, 0, name);
}
}

大致的调用顺序图如下:

SourceMonitor分析结果如下:

第八次大作业
本题新增内容:
1)增加管脚电压的显示
在输出每个电器的状态信息后,再依次输出该电器每个管脚的电压。(格式详见输出信息部分)
2)电流限制
电器在工作时,过大的电流会引起电器过热,从而烧坏电路。本次迭代,每个元器件都有最大电流的设置,当实时电流超过最大电流时,在该电器输出信息的最后加入提示“exceeding current limit error”,与前面的信息之间用英文空格分隔。
例如:@B1:190 68-17 exceeding current limit error
本题各类电器的最大限定电流如下:
开关20、分档调速器18、连续调速器18、白炽灯9、日光灯5、吊扇12、落地扇14、互斥开关20、受控窗帘12、二极管8。
3)短路检测
如果电路出现无穷大的电流造成短路,所有元器件信息不输出,仅输出提示“short circuit error”
4)并联电路中包含并联
本次迭代考虑并联电路中包含并联电路的情况,即构成并联电路的串联电路可以包含别的并联电路。例如如下输入的电路,并联电路M2的其中一条串联电路T4中包含了另一条并联电路M1:
#T1:[IN D2-1] [D2-2 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
5)二极管
增加二极管元件,其电路特性为:正向导通,反向截止;其电器符号如图4所示,当电流从左至右流过时,二极管导通”conduction”,电阻为0;电流从右至左流动时,二极管截止”cutoff”,电阻无穷大,相当于开关打开。
二极管的标识符为’P’,左侧管脚编号为1,右侧管脚编号为2。

二极管如果两端电压相等,没有电流流过,分以下两种情况输出:
1、如果两端电压为0,二极管的导通/截止状态由接入方向决定,1号引脚靠近电源则状态为导通,反之为截止。
2、如果两端电压不为0,二极管导通。
新增内容分析
增加管脚电压的显示
这部分内容要求在输出每个电器的状态信息后,再依次输出该电器每个管脚的电压。这意味着在电路设计中,需要增加对每个电器管脚电压的监测和显示功能。
电流限制
当电器工作时,过大的电流会引起电器过热,从而烧坏电路。因此,每次元器件都有最大电流的设置,当实时电流超过最大电流时,在该电器输出信息的最后加入提示 “exceeding current limit error”,并在前面的信息之间用英文空格隔开。
列出了各类电器的最大电流限制,例如开关、分相调速器、连续调速器等。
短路检测
如果电路出现无穷大的电流造成短路,所有元器件信息不输出,仅输出提示 “short circuit error”。这是为了防止短路对电路造成损害。
并联电路中包含并联
这部分讨论了并联电路中包含并联的情况,即构成并联电路的串联电路可以包含别的并联电路。给出了一个具体的例子来说明这种复杂的电路结构。
二极管
增加了二极管元件,其电路特性为正向导通,反向截止。二极管的符号如图 2 所示,当电流从左至右流动时,二极管导通(“conduction”),电阻为 0;当电流从右至左流动时,二极管截止(“cutoff”),电阻无穷大,相当于开关打开。
二极管的标识符为 “P”,左侧管脚编号为 1,右侧管脚编号为 2。
当二极管两端电压相等时,没有电流流过,分为以下两种情况输出:
如果两端电压为正,二极管的导通 / 截止状态由输入状态决定,正向为导通,反向为截止。
如果两端电压为负,二极管不导通。
这些新增内容主要是为了提高电路的安全性和可靠性,通过增加电压和电流监测、短路检测以及引入二极管来控制电流流向,确保电路在正常工作范围内运行,能让我体会到在一次又一次的迭代中电路的设计越来越贴合现实,其中循序渐进的思考过程让我受益其中。
电路结构变化
迭代 4 相较于前三次迭代新加的内容是:在一条并联电路中可能包含其他并联电路。这意味着在迭代 4 中,电路的并联结构变得更加复杂,可能出现多层嵌套的并联关系,而不仅仅是简单的串联或并联组合。这种设计可以用于实现更复杂的电路功能,例如在需要对多个支路进行独立控制或组合控制的情况下。

设计建议:
1、电路设备类:描述所有电路设备的公共特征。
2、受控设备类、控制设备类:对应受控、控制设备
3、串联电路类:一条由多个电路设备构成的串联电路,也看成是一个独立的电路设备
4、并联电路类:继承电路设备类,也看成是一个独立的电路设备
下面是我部分类的设计思路
本次大作业我在上一次的大作业基础上重新构造了Equipment类。下面列出了它的属性和一些方法:
Equipment类
作用:作为一个抽象类,作为其他具体设备类的基类,定义了一些设备共有的属性和抽象方法,用于规范子类的行为。
属性:
switchstyle:用于表示开关样式相关的属性。
voltage:设备的电压值。
resistor:设备的电阻值。
name:设备的名称。
contact1、contact2:可能用于表示设备的连接点等相关属性。
方法:
getSwitchstyle():获取开关样式属性值。
IfPathway():用于判断设备是否构成通路,默认返回false,子类可根据具体情况重写。
getVoltage():获取设备的电压值。
setVoltage(double c):抽象方法,用于设置设备的电压值,子类必须实现。
getResistor():抽象方法,用于获取设备的电阻值,子类必须实现。
getContact1()、setContact1(double contact1):用于获取和设置contact1属性值。
getContact2()、setContact2(double contact2):用于获取和设置contact2属性值。
getName():获取设备的名称。
display():抽象方法,用于展示设备的相关信息,子类必须实现。
close():抽象方法,用于关闭设备或执行相关操作,子类必须实现。
FloorFan类
作用:继承自Equipment类,表示落地扇设备,根据设置的电压值来确定落地扇的转速。
属性:
speed:表示落地扇的转速。
方法:
FloorFan(String name):构造函数,用于创建落地扇对象并设置其电阻值和名称。
setVoltage(double c):根据传入的电压值经过一系列计算来设置落地扇的转速。
getResistor():重写父类方法,返回落地扇的电阻值。
display():重写父类方法,展示落地扇的名称和转速值。
close():重写父类方法,将落地扇转速设置为0,即关闭落地扇。
compareTo(FloorFan o):实现Comparable接口的方法,用于按照名称对落地扇对象进行比较排序。
添加了串联电路相关操作和属性的类:
Series类
作用:用于表示串联电路相关的操作和属性,管理一系列设备,可进行电压分配、通路检查、短路检查等操作。
属性:
voltage:串联电路的电压值。
name:串联电路的名称。
resistor:串联电路的总电阻值。
list:存储串联电路中的设备列表。
方法:
getVoltage()、setVoltage(double voltage):用于获取和设置串联电路的电压值。
getName()、setName(String name):用于获取和设置串联电路的名称。
VoltageDivision():根据串联电路的总电阻和各设备电阻进行电压分配操作。
getResistor():计算并返回串联电路的总电阻值。
IfPathway():检查串联电路是否构成通路。
Ifshort():检查串联电路是否短路。
getList()、setList(List<Equipment> list):用于获取和设置串联电路中的设备列表。
addEquipment(Equipment e):向串联电路中添加设备。
getEquipment(int index):获取串联电路中指定索引的设备。
点击查看代码
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 (Equipment e : list) {
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 (Equipment e : list) {
if (e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor)
continue;
else
resistor += e.getResistor();
}
return resistor;
}
public boolean IfPathway() {
for (Equipment e : list) {
if (e instanceof Switch) {
if (e.switchstyle == 0) {
return false;
}
} else if (e instanceof Parallel && !e.IfPathway()) {
return false;
}
}
return true;
}
public boolean Ifshort() { // 检查是否短路
for (Equipment e : list) {
if (e instanceof Switch && e.switchstyle == 1) {
return false;
}
}
return true;
}
public List<Equipment> getList() {
return list;
}
public void setList(List<Equipment> list) {
this.list = list;
}
private List<Equipment> list;
Series() {
list = new ArrayList<>();
}
public void addEquipment(Equipment e) {
list.add(e);
}
public Equipment getEquipment(int index) {
return list.get(index - 1);
}
}
Parallel类
作用:继承自Equipment类,用于表示并联电路相关的操作和属性,管理多个串联电路组成的并联电路,可进行电压设置、通路检查等操作。
属性:
seriesList:存储组成并联电路的各个串联电路列表。
方法:
Parallel(List<Series> seriesList):构造函数,用于创建并联电路对象并传入组成它的串联电路列表。
setVoltage(double c):根据并联电路是否通路来设置各串联电路的电压并进行电压分配操作。
IfPathway():检查并联电路是否构成通路。
getResistor():计算并返回并联电路的等效电阻值。
display()、close():重写父类方法,这里为空实现。
点击查看代码
class Parallel extends Equipment {
private List<Series> seriesList;
Parallel(List<Series> seriesList) {
this.seriesList = seriesList;
}
@Override
public void setVoltage(double c) {
for (Series series : seriesList) {
if (series.IfPathway()) {
series.setVoltage(c);
series.VoltageDivision();
}
}
}
@Override
public boolean IfPathway() { // 检查并联是否通路
for (Series series : seriesList) {
if (series.IfPathway()) {
return true;
}
}
return false;
}
@Override
double getResistor() {
for (Series series : seriesList) {
if (series.Ifshort()) {
return 0;
}
}
double r = 0;
double R = 0;
for (Series series : seriesList) {
if (series.IfPathway()) {
R += (1.0 / series.getResistor());
}
}
return (1.0 / R);
}
@Override
void display() { }
@Override
void close() { }
}
Diode类
作用:通过继承 Equipment 类并实现其抽象方法,实现了二极管的相关功能和操作,根据输入电压判断是否导通,并可以显示自身的信息和执行关闭操作。
属性:
conduction:用于表示二极管是否导通的布尔型变量,初始化为 false。
构造函数:
public Diode(String name, double voltage, double resistor):接收二极管的名称、电压和电阻作为参数,并调用父类的构造函数初始化这些属性,同时将 conduction 初始化为 false。
方法重写:
IfPathway():根据二极管的特性,当电压大于等于 0 时,将 conduction 置为 true,表示导通,否则置为 false,表示截止。
setVoltage(double c):首先调用父类的 setVoltage 方法设置电压,然后调用 IfPathway 方法更新导通状态。
getResistor():调用父类的 getResistor 方法获取电阻。
display():打印出二极管的名称、电压、电阻和导通状态。
close():将二极管的电压设置为 0,可视为关闭操作,可根据实际需求修改。
Main类
作用:包含main方法,作为程序的入口点,用于读取用户输入的信息,创建各种设备对象并将它们添加到相应的电路(串联或并联)中,然后根据用户输入设置相关设备参数,最后检查电路是否通路并进行相应操作(如分压、展示设备信息等)。
以上是我根据题目相关要求初步设计的类图和方法的一个大致思路,下面是一个我的详细类图:

调用顺序图如下:

SourceMonitor分析结果如下:

踩坑心得:
在本次电路模拟程序的开发过程中,我遇到了一系列颇为棘手的问题,给整个项目的实现带来了不少挑战。
- 首先,让我深感困扰的是短路检测功能的实现问题。短路检测本应是确保电路安全稳定运行的关键环节,但目前的实现却存在严重的准确性问题。具体来说,在现有的短路检测机制中,我只考虑了部分较为简单和直观的短路情况,而对于一些复杂的间接短路情况却有所忽视。例如,在涉及互斥开关的电路中,由于其独特的结构和工作原理,可能会引发间接短路现象。这种间接短路可能并不像我想象的那样仅仅是电源直接连接到地的简单情况,它还可能通过互斥开关的不同状态以及其他中间设备(包括各种开关、互斥开关等)之间的间接连接而产生。而且,更为复杂的是,在电路模拟的动态过程中,设备的状态会不断发生变化,这是一个容易被忽视的重要因素。像开关的开合操作,会导致电路的连接情况发生改变,进而影响短路路径的形成与否。原本看似正常的电路,在某些设备状态改变后,可能就会出现短路,但我的检测系统却未能及时察觉。这就使得我不得不采用一种较为繁琐且效率低下的方式来检查短路情况,即只能通过遍历整个电路或者通过调试工具来手动查看电路结构,逐一检查是否存在从电源到地的低电阻路径。这种方式不仅耗时费力,而且极易出错,严重影响了程序的性能和准确性,使得短路检测功能无法发挥其应有的作用,给整个电路系统的稳定性带来了巨大的隐患。
其次,在电流计算方面也出现了严重的错误。在计算设备的电流时,我原本的计算方法没有考虑到一个重要的物理特性,那就是设备电阻会随着设备状态的改变而发生变化。这是一个非常关键的因素,却被我不小心遗漏了。以二极管为例,它的电阻特性是在导通时为 0,而在截止时电阻又会呈现出不同的值。然而,我在设计电流计算逻辑时,并没有将这种设备状态对电阻的影响考虑进去。这就导致在计算电流时,由于使用了错误的电阻值,最终的计算结果与实际情况相差甚远。这种情况让我困扰了相当长的一段时间,因为电路中的设备众多,它们各自具有不同的电阻,而且不同设备在不同状态下电阻的变化又十分复杂。我最初在计算电流时,只是简单地将电路中的设备视为固定电阻,而忽略了它们在不同工作状态下电阻的动态变化。这就使得在计算各路电流时,需要分各种复杂的情况进行计算,而我又未能全面涵盖这些情况,导致计算结果的准确性大打折扣。为了解决这个问题,我不得不对电流计算的整个过程进行重新审视和修改,在计算电流的过程中,需要根据设备的当前实际状态动态调整其电阻值,并且每次设备状态发生变化时,都要重新计算电流,这无疑增加了计算的复杂性和计算量,但却是确保电流计算准确的必经之路。
再者,设备状态更新的逻辑也出现了错误。设备状态更新在整个电路模拟系统中起着至关重要的作用,它涉及到整个电路的状态变化和性能表现。然而,实际情况是,设备的状态更新逻辑相当复杂,涉及到多个设备之间的相互关联和交互,以及不同设备在不同条件下的状态变化规则。在实现过程中,我发现自己很容易遗漏某些情况,这就导致设备状态的更新无法正确反映电路的实际变化。为了验证设备状态更新逻辑是否正确,我不得不对每个设备的状态更新过程进行细致入微的检查,逐个部分查看,试图找出可能存在的问题。这种方式就像大海捞针一样,不仅效率低下,而且容易出错,使得设备状态更新的功能无法稳定可靠地实现,进而影响整个电路模拟系统的正常运行。 - 最后,输入解析方面的问题是我出现最为频繁的问题,也是最让我头疼的一个环节。在解析输入信息时,由于输入信息的格式复杂多样,包含了各种不同类型的设备信息、连接信息、控制信息以及电路结构信息等,这些信息的格式都有其特定的规则和约定。在解析这些信息时,由于规则复杂,很容易出现解析错误,进而导致程序崩溃。尤其是在处理字符串信息时,字符串解析错误频繁发生。例如,在解析设备标识符、引脚信息、连接信息等方面,由于输入的格式可能会出现细微的偏差或者不完整,我们的解析程序就无法正确识别这些信息,从而导致程序无法正常运行。这种情况发生时,我经常会看到一大堆报错信息,或者更糟糕的是,程序直接崩溃而没有任何报错信息,这就意味着我需要花费大量的时间和精力去查找问题所在。为了解决这个问题,我只能增加输入验证的逻辑,在对输入信息进行解析之前,先对其进行严格的验证,确保输入信息完全符合我们预定的格式要求。同时,为了防止程序因输入错误而崩溃,我还使用了异常处理机制,以便能够捕获并妥善处理可能出现的各种输入错误,尽量避免程序因为输入解析错误而中断运行,但这也增加了程序的复杂性和维护成本。
- 这些问题的出现,让我意识到在电路模拟程序的开发过程中,需要更加细致和深入地考虑各种实际情况和复杂因素,对电路的物理特性和程序的逻辑处理都要有更全面的理解和把握,以避免类似的错误再次发生
改进建议
- 在本次电路模拟程序的开发中,我需要对现有的一些功能进行改进和完善。首先是短路检测方面,我现有的短路检测算法存在明显的不足,它仅侧重于检查从电源到地的直接路径,而对于整个电路的复杂情况考虑不够周全。实际上,我应该对整个电路图进行深入遍历,全面考虑可能的短路路径,尤其是通过诸如开关、互斥开关等中间设备形成的间接短路路径。这是因为在一个复杂的电路中,中间设备的各种连接和状态组合可能会形成一些隐蔽的短路情况,而不仅仅是简单的电源直接接地。并且,电路是动态的,其中设备的状态会随着模拟过程而不断变化,像开关会进行开合操作,这些操作会对电路的连接状态产生重大影响,所以短路检测不能是一次性的静态操作,而必须在每次设备状态更新后都重新进行,这样才能确保及时发现潜在的短路隐患,保证电路在模拟过程中的安全性和稳定性。
- 同时,为了准确计算电路中的电流,我要为每个设备建立一个动态电阻模型。以二极管为例,它的电阻会根据导通和截止状态发生显著变化,在导通时电阻近乎为零,截止时电阻则不同。所以我要让这个动态电阻模型能够依据设备的当前状态,精确地调整其电阻值。在计算电流时,就可以使用该模型提供的电阻值代入电路方程求解,避免因使用固定电阻值而导致的电流计算错误,使计算结果更符合电路的实际情况。
- 由于电路中的电流和电压相互依赖,它们之间的关系可以通过电路方程来描述,但直接求解这些方程往往比较困难,因此我可能需要采用迭代的方法。在迭代求解过程中,我会根据当前的电压分布来计算电流,然后依据计算出的电流更新电压分布,如此反复,就像一个逐步逼近的过程,直到电压和电流都稳定收敛到一个合理的值,这样可以更准确地模拟电路的实际运行状况。
- 对于设备状态更新逻辑,我也需要进一步完善。目前该逻辑比较粗糙,存在一些问题,会导致无法准确反映电路的实际状态变化。我需要对其进行详细的审查和测试,要考虑到各种可能的场景,包括不同设备之间的相互影响、不同输入信号下的状态响应以及不同设备组合的状态更新,确保这个逻辑能够覆盖所有可能出现的情况,避免遗漏。
- 另外,我要对代码进行重构和优化,以提高代码的质量。目前我的代码在类和方法的职责划分上可能不够清晰,存在一些冗余,这会影响代码的可读性和可维护性。我要对代码进行重构,让类和方法各自承担明确的职责,减少冗余代码,让代码更加简洁明了,便于后续的开发和维护工作。
- 最后,在输入处理方面,我要增强输入处理能力。输入信息通常具有复杂多样的格式,而目前我的输入解析容易出现错误,进而导致程序崩溃。为了避免这种情况,我要在解析输入信息之前增加严格的验证步骤,确保输入数据严格符合预定的格式和规范。而且,我要将程序划分为多个模块,每个模块负责一个特定的功能,通过清晰的接口和继承关系来组织类和方法,这样可以减少代码冗余,提高代码的复用性,让程序的整体结构更加清晰和易于维护,从而提升整个电路模拟程序的可靠性和性能。
学习总结:
- 通过本阶段的两次题目集练习,我在面向对象编程领域取得了令人欣喜的进步,对其核心概念与设计理念的认知达到了更为深入且透彻的程度。
- 在面向对象编程的实践过程中,抽象类与接口的使用展现出了其强大的优势,成为了我构建稳固、灵活且具备高扩展性代码架构的关键要素。抽象类作为一种特殊的基类,允许我对一系列对象的共性方法和属性进行定义,其中抽象方法是它的一大特色,这些抽象方法为子类提供了必须遵循的实现框架。在不同的子类中,我们可以根据具体的业务需求对这些抽象方法进行具体实现,这样一来,确保了代码的一致性和规范性得到了强有力的保障。就拿实际情况来说,当我需要处理多个对象,它们虽然具有相似的行为,但又存在一些细微的差别时,抽象类就发挥了巨大的作用。我可以精准地将这些对象所共有的特性抽象出来,定义在抽象类中,为这些对象提供一个统一的基础框架。这样,各个子类便可以在这个框架的基础上,根据自身的特点和业务需求,进行个性化的扩展和细化。这种基于抽象类的代码复用方式,极大地提高了代码的可重用性,避免了在不同子类中重复编写相同逻辑的代码,减少了代码量,使得代码结构更加简洁明了。而且,在后续的维护过程中,由于代码逻辑集中在抽象类和各个子类的特定实现中,维护人员能够更轻松地找到需要修改的部分,极大地降低了维护的难度和成本,让整个代码体系呈现出清晰易懂的良好状态,为后续的开发工作提供了极大的便利。
- 同时,我对重复代码的危害有了更为深刻的认识。在编程实践中,重复代码犹如一种无形的 “毒瘤”,它会给代码库带来诸多负面影响。首先,它会显著增加代码的长度,让代码库变得臃肿不堪,使代码的可读性大大降低。更重要的是,在维护时会带来极大的麻烦,因为当需要对重复代码所涉及的逻辑进行修改时,我们必须在多个位置进行相同的操作,稍有不慎,就可能会遗漏其中的某些部分,从而导致代码出现错误,并且很难察觉。为了避免这种情况的发生,我学会了仔细审查代码,就像一个侦探一样,不放过任何一处可能存在的重复代码。一旦发现,我会将其中的通用逻辑提取出来,将其封装为独立的方法或类,以便在不同的场景中进行复用。这种优化不仅可以提高代码的可维护性,还能提升代码的性能。特别是对于那些涉及重复计算的部分,我会进行优化处理,避免多次执行相同的复杂数学运算或数据处理操作,以节省计算资源,提高代码的执行效率。例如,在处理涉及复杂数学公式计算或数据处理的场景中,我会将其封装为专门的工具类方法,这样,在需要使用该计算逻辑的地方,只需要简单地调用该方法即可,确保了计算结果的一致性和准确性,同时也提高了代码的运行速度,让程序更加高效。
- 另外,正则表达式的学习和运用也为我的编程技能增添了新的亮点。正则表达式就像是一把万能钥匙,可以打开各种文本处理的大门,它是一种功能强大的文本处理工具,能够以简洁、高效的方式处理各种复杂的输入字符串。在诸多场景中,如处理用户输入、读取文件中的文本信息以及对输入数据进行验证时,正则表达式都展现出了不可替代的优势。它使我的代码具备了更强的适应性和灵活性,能够轻松应对不同格式的输入数据,能够迅速地从大量的数据中提取出所需的信息,并进行相应的处理。以用户输入的表单数据为例,通过精心设计的正则表达式,可以快速地对输入的格式进行验证,确保其符合我们预先设定的格式要求,无论是对用户的姓名、邮箱地址、电话号码还是其他信息的验证,都能做到既准确又高效,极大地增强了程序与用户之间的交互性,确保输入数据的质量和准确性。
- 在代码编写的实践中,我越发认识到设计模式的重要性和实用性,它就像建筑中的蓝图,为我们提供了经过实践检验的优秀解决方案,帮助我们解决各种常见的编程问题。例如,模板方法模式是一个非常实用的设计模式,它为我们定义了一个算法的基本骨架,将其中某些步骤的具体实现延迟到子类中,这就使得子类在遵循算法整体结构的前提下,能够灵活地对部分步骤进行定制化处理。这种模式在处理具有固定流程但部分环节需要根据不同情况进行调整的业务逻辑时,效果显著,它能够极大地提高代码的复用性和扩展性。再比如策略模式,它赋予了程序在运行时根据不同的条件选择不同算法或行为策略的能力,让代码能够动态地适应各种变化的需求。通过巧妙地运用这些设计模式,我能够将复杂的业务逻辑拆解为多个简单、独立的组件,每个组件专注于完成特定的任务,降低了代码之间的耦合度。低耦合的代码结构让代码的各个部分之间的关系更加清晰,易于理解和维护。当业务需求发生变化时,我们只需要对相关的组件进行修改或替换,而不会对整个系统造成大规模的影响,从而使代码具有更高的灵活性和可维护性,这在实际开发中是非常重要的,能够让我们更加从容地应对各种变化。
- 然而,我也清楚地意识到自己的一些不足之处。异常处理是我在之前的编程实践中容易忽视的一个重要方面。在程序的实际运行环境中,异常情况是不可避免的,可能会出现各种问题,比如文件读取失败、网络连接中断、数据类型不匹配等。如果在代码中没有完善的异常处理机制,程序在遇到异常时很可能会突然崩溃,这会给用户带来糟糕的体验,甚至可能会导致数据丢失或者系统故障等严重后果。因此,在后续的代码编写过程中,我会仔细分析每一个可能出现异常的环节,为其添加合适的异常处理代码。以文件读取操作为例,我会使用 try-catch 块来捕获可能出现的 IOException 异常,一旦发生异常,在 catch 块中,我会根据具体情况进行相应的处理,可能会向用户提示文件读取失败的原因,或者尝试提供一些替代的解决方案,确保程序在面对异常时能够保持稳定运行,或者至少能向用户提供合理的反馈信息,让用户了解当前的异常状态,这极大地增强了代码的健壮性和可靠性,为程序的稳定运行提供了有力的保障。
- 还有,编写测试用例和熟练运用调试工具是我在本次练习中着重提升的技能。测试用例如同代码的质量检验员,它们能帮助我在代码开发的各个阶段,及时发现潜在的问题和漏洞。我会编写全面、细致的测试用例,对代码的不同功能模块进行系统性的测试,覆盖各种可能的输入情况,包括正常输入、边界输入以及异常输入等,确保代码在各种场景下都能正确运行。而调试工具则是我在解决代码问题时的得力助手,当代码出现问题时,我可以通过设置断点、逐步执行代码、查看变量的值等调试手段,深入到代码的执行流程中,像医生一样,精确地找到问题的根源,并及时进行修复。这种深入的调试过程,不仅提高了我解决问题的效率,还让我对代码的运行机制有了更深入的理解,有助于我进一步优化代码的质量,让代码更加健壮。
- 最后,编写代码本质上是一个不断解决问题的过程,而这两次题目集的练习教会了我一种行之有效的方法 —— 将一个庞大复杂的问题分解为多个更小、更易于管理和解决的子问题。这种分而治之的策略,让我在面对编程任务时不再感到无从下手。我可以有条不紊地对每个子问题进行分析、设计和实现,将每个子问题视为一个小的项目,通过解决一个个子问题,最终完成整个编程任务。在这个过程中,我深刻体会到编程并不是一帆风顺的,特别是在调试和解决 bug 的阶段,往往会遇到各种困难,一个看似微不足道的 bug 可能隐藏得很深,需要反复排查和调试才能找到。但是,通过这些不断的尝试和改进,我逐渐培养了自己的耐心和毅力,学会了在困难和挫折面前保持冷静,坚持不懈地寻找解决方案。这种心态的转变对于我在编程领域的长远发展具有深远的影响,让我更有信心和能力去应对未来的各种挑战。
- 综上所述,经过这两次题目集的练习,我在面向对象编程的知识和技能方面实现了全方位的提升。我对抽象类、接口、设计模式等核心概念和技术的应用更加熟练,在代码质量、可维护性、健壮性以及问题解决能力等多个方面都取得了显著的进步,这些进步将为我今后在实际开发工作中应对各种复杂挑战和多样化需求提供坚实的基础,让我在编程之路上迈出更加稳健的步伐。
学期总结以及本学期的收获
在本学期的 JAVA 面向对象程序课程中,我取得了显著的学习成果,同时也对自身的编程能力有了更为清晰的认知。
课程开始时,我深入学习了类和对象的概念。我明白了类是创建对象的模板,它定义了对象的属性和方法。通过使用 class 关键字,我可以创建各种各样的类,为其添加成员变量和成员方法,例如定义一个 Person 类,包含 name 和 age 等属性以及 speak 方法,而对象则是类的具体实例。实例化对象的过程让我感受到了将抽象概念转化为实际应用的乐趣,我可以根据需要创建多个对象,并对它们的属性和方法进行操作,这为我构建复杂的程序提供了基础。
在学习封装时,我意识到这是一种保护数据和代码的重要手段。通过将类的属性设置为私有,使用 private 关键字,并提供公共的访问器和修改器方法(getter 和 setter),我可以控制外部对类内部数据的访问和修改,有效防止了数据的非法操作。继承则为代码的复用和扩展带来了极大的便利,我可以创建一个父类,如 Animal,再创建多个子类,如 Dog 和 Cat,子类可以继承父类的属性和方法,同时又能根据自身需求添加新的特性,这极大地减少了代码的重复编写。多态是我学习的一个亮点,它允许不同对象对同一消息做出不同响应,通过使用父类引用指向子类对象,结合方法的重写,使程序在运行时更加灵活,可扩展性更强,比如不同动物发出叫声的实现就很好地体现了多态的优势。
抽象类和接口为我打开了构建代码架构的新大门。抽象类让我可以定义一些具有共性的方法和属性,但部分方法可留待子类具体实现,而接口则为不同类之间定义了一种契约,确保它们都实现某些共同的方法。例如,定义一个 Shape 抽象类和 Drawable 接口,让不同形状的类可以根据自身情况实现具体细节。
在实践方面,设计模式的学习给我带来了极大帮助。像工厂模式,我可以创建一个工厂类来根据不同条件生成不同的对象,避免了对象创建的复杂性,提高了代码的组织性和可维护性。
而异常处理部分的学习,更是让我受益匪浅。在课程中,我认识到异常是程序运行过程中可能出现的各种意外情况,如文件读取错误、网络连接中断、输入不合法等。使用 try-catch 语句让我掌握了处理异常的基本方法,我可以将可能出现异常的代码放在 try 块中,当异常发生时,程序会立即跳转到相应的 catch 块进行处理。这不仅避免了程序的崩溃,还能让我根据不同的异常类型做出针对性的处理。比如在文件读取操作中,当发生 IOException 时,我可以输出错误信息,提示用户文件可能不存在或无法访问;在进行数据解析时,如果出现 NumberFormatException,我可以引导用户输入正确的格式。这种异常处理机制极大地增强了程序的健壮性和用户体验,让程序在各种可能出现意外的情况下都能有合理的反馈和处理方式,确保程序能够继续正常运行或优雅地退出。同时,我还学习了 finally 块,它可以确保无论是否发生异常,一些必要的清理工作,如关闭文件流、释放资源等操作都能得以执行,使程序更加严谨和可靠。
然而,我也清楚地认识到自己的不足之处。在编写代码时,我有时会写出冗余的代码,导致程序显得臃肿,这不仅影响了代码的可读性,也降低了性能。在处理复杂逻辑,尤其是涉及多线程、算法优化等方面,我的经验和技巧还不够丰富,这会导致程序运行效率不高。但这些都是我未来努力的方向,我会在后续的学习中不断加强对 JAVA 的理解和运用,通过不断实践和学习新的知识,逐步提升自己的编程水平,将所学知识融会贯通,为开发出更优质、高效的程序而努力。
- 最后我的建议是希望老师可以在PTA将测试点写的更为详细一些,因为课程很多,编写代码就要占大部分课后写作业的时间,而找这些测试点就更占时间,我觉得对我来说不可能把所有的时间都用来学习JAVA上,还有其它的专业课需要钻研,我知道老师不给测试点是为了锻炼我们分析题目,培养我们思考逻辑的能力,但还是希望老师能在这方面多一些些的引导,非常感谢蔡轲老师这个学期对我的谆谆教诲,通过面向对象程序设计的学习,让我对于编程叩开了一扇厚重的大门,让我见识到了编程世界的广阔与浩瀚!

浙公网安备 33010602011771号