一、前言
这两次大作业中关于电路的分析与设计的开发让我对java这门语言的理解和应用又得到了提升,面向对象的编程对于解决实际生活中的问题拥有其他编程方式所没有的优势。在两次的类设计中我的考虑并不周全,忽视了
电路设备之间共性从而没怎么用到继承,这个问题在第一次串联电路的大作业中还说的过去,但是到了第二次并联电路的时候就变得十分要命了,我的并联电路和串联电路是两个完全独立的类,这让我在后续电路处理中
十分的棘手。总的来说,这两次大作业十分考验我类的设计和面向对象的编程思维。
二、第一次大作业
第一次大作业因为是首次接触到电路设计的编程题,尽管对串联电路的知识在初高中的时候已经学的相当多了,然而把知识转化为类设计和代码还是有相当大的挑战的。首先在一开始的类设计中,我先给题目中出现的设备
创建了一个Device类作为所有设备的父类。
点击查看代码
// 基础设备类
abstract class Device {
protected String id;
protected double inputVoltage = 0; // 输入电压
protected double outputVoltage = 0; // 输出电压
public Device(String id) {
this.id = id;
}
public abstract void updateState(); // 更新设备的状态
public String getId() {
return id;
}
public double getOutputVoltage() {
return outputVoltage;
}
public void setInputVoltage(double voltage) {
this.inputVoltage = voltage;
}
public void setoutputVoltage(double voltage) {
this.outputVoltage = voltage;
}
public abstract boolean isControlled(); // 是否被控制或连接
}
然后就是题目中给出的各个设备的类设计了,一开始我忽视了受控设备和控制设备的区别,直接让所有的设备都继承Device类,这个错误很快在后续的电压传递处理中让我意识到了,于是后续修改后,我将白炽灯、吊扇
等受控设备继承自受控设备类;开关、分档调速器等控制设备继承自控制设备类。受控设备类和控制设备类的差别在于受控设备多了一个markAsConnected()方法,意在受控设备在输入匹配的情况下调用该方法来标记设备
在电路中以用于后续的打印。
点击查看代码
// 受控设备类
abstract class ControlledDevice extends Device {
private boolean connected = false; // 是否被连接
public ControlledDevice(String id) {
super(id);
}
public void markAsConnected() {
connected = true;
}
@Override
public boolean isControlled() {
return connected;
}
}
在处理完各设备的类设计于继承关系后,我开始着手设计电路类。首先我声明了三个存储工具分别用于存储设备、设备两两关系、电路连接。
点击查看代码
, ``` private List电路类中connect方法是标记设备电路中连接关系的重要方法,其实现思路是:首先通过输入匹配到的id来获取对应devices 数组中的设备,在得到两个设备后判断id1是不是VCC和id2是不是GND,前者连接设备的输入电压
要置为220V、后者连接设备的输出电压要置为0V。在考虑过这两种情况后,才是两个普通设备的连接,在connections 哈希表中标记两个设备的连接。
点击查看代码
else {
connections.put(id1, id2);
// 标记设备为已连接
if (device1 instanceof ControlledDevice) {
((ControlledDevice) device1).markAsConnected();
}
if (device2 instanceof ControlledDevice) {
((ControlledDevice) device2).markAsConnected();
}
}
电路类中另一方法updateAllDevices方法用于更新所有设备的状态(包括输入输出电压、开关开闭、调档器档位等),以及根据连接关系传递电压。
首先更新所有设备的状态,即调用各个设备自身具备的updateState()方法。
点击查看代码
// 先更新控制设备的状态
for (Device device : devices) {
if (device instanceof ControlDevice) {
device.updateState();
}
}
// 再更新受控设备的状态
for (Device device : devices) {
if (device instanceof ControlledDevice) {
device.updateState();
}
}
public void updateAllDevices() {
// 先更新控制设备的状态
for (Device device : devices) {
if (device instanceof ControlDevice) {
device.updateState();
}
}
// 根据连接关系传递电压
for (String id1 : connections.keySet()) {
String id2 = connections.get(id1);
Device device1 = deviceMap.get(id1);
Device device2 = deviceMap.get(id2);
if (device1 != null && device2 != null) {
device2.setInputVoltage(device1.getOutputVoltage());
}
}
// 再更新受控设备的状态
for (Device device : devices) {
if (device instanceof ControlledDevice) {
device.updateState();
}
}
}
编写完电路类Circuit后,我开始编写Main类。现在尚未完成的工作首先是从输入中匹配出所需的设备名、id号、连接关系、设备状态等信息,在这里我采用了正则表达式,这个方法可以高效的提取出所需的信息。
下面是第一次大作业Main函数的主要流程
导入必要的类:
Scanner:用于从控制台读取输入。
Circuit:电路类,用于管理电路中的设备和连接。
Switch、StepRegulator、ContinuousRegulator、CeilingFan、IncandescentLamp、FluorescentLamp:这些是电路中的设备类。
创建Circuit对象:
Circuit circuit = new Circuit();:创建一个电路对象,用于管理电路中的设备和连接。
创建设备实例:
创建了7个设备实例:两个开关(k1和k2)、两个调速器(一个步进调速器f1和一个连续调速器l1)、三个吊扇(d1、d2、d3)、一个白炽灯(b2)和一个荧光灯(r2)。
将设备添加到电路:
使用circuit.addDevice(device)方法将所有创建的设备添加到电路中。
定义正则表达式:
connectionPattern:用于解析设备之间的连接信息。
controlPattern:用于解析对设备的控制信息(如开关操作、调速操作)。
读取和解析输入:
使用Scanner对象从控制台读取输入,直到输入"end"。
对于每一行输入,使用connectionPattern和controlPattern正则表达式进行匹配。
如果匹配connectionPattern,则解析出两个设备名,并使用circuit.connect(device1, device2)方法将它们连接起来。
如果匹配controlPattern,则解析出设备ID、操作(增加或减少)和速度值(如果有),然后根据设备类型执行相应的操作。
处理异常:
如果在解析或执行操作时发生异常,会捕获异常并可以选择打印错误信息(在这段代码中被注释掉了)。
更新设备状态:
使用circuit.updateAllDevices()方法更新电路中所有设备的状态。
打印设备状态:
使用circuit.printAllStates()方法打印电路中所有设备的状态。
使用匹配[VCC K1-1]式连接信息的正则表达式:
Pattern connectionPattern = Pattern.compile("\[(\w+)-?(\d) (\w+)-?(\d)\]");
匹配#K1式控制信息的正则表达式:
Pattern controlPattern = Pattern.compile("#(\w+)([+-]?)(