第二次总结

Java课程的第二次迭代作业结束了,这一次以数字电路模拟程序为中心,不断增加新的功能来完善该系统,通过这一次,我学到了很多,以下我将通过代码分析来总结这3次作业的情况。

第一次作业

作业要求

1、电路元件
电路中包含与门、或门、非门、异或门、同或门五种元件。元件特征如下:

与门:
包含两个或多个输入引脚和一个输出引脚。所有输入引脚必须都是高电平,输出引脚才是高电平,只要有一个输入引脚为低电平,输出引脚输出低电平。

或门:
包含两个或多个输入引脚和一个输出引脚。所有输入引脚必须都是低电平,输出引脚才是低电平,只要有一个输入引脚为高电平,输出引脚输出高电平。

非门:
包含一个输入引脚和一个输出引脚。输出引脚的电平与输入引脚的电平相反,如输入为低电平,输出则为高电平。

异或门:
包含两个输入引脚和一个输出引脚。当两个输入引脚电平不一致时输出引脚输出高电平,否则输出低电平。

同或门:
包含两个输入引脚和一个输出引脚。当两个输入引脚电平一致时输出引脚输出高电平,否则输出低电平。

2、程序输入
1)元件信息:
用A、O、N、X、Y 分别用作与门、或门、非门、异或门、同或门五种元件的元件标识符。
电路中的每个与门、或门用“标识符(输入引脚数)+编号”作为其元件名。
例如:A(8)1表示一个8输入引脚的与门,O(4)2代表一个4输入引脚的或门。
电路中的每个非门、异或门、同或门用“标识符+编号”作为其元件名。
例如:X8表示一个异或门,Y4代表一个同或门,N1代表一个非门。
约束条件:
不同元件的编号可以相同,如X4、Y4。
同一电路中同种元件的编号不可重复,可以不连续

2)引脚信息:
引脚信息由“元件名-引脚号”构成,。
例如:A(8)1-2代表与门A(8)1的2号引脚。

3)电路的输入信息:
电路的输入格式:
INPUT:英文空格+输入1+”-”+输入信号1+英文空格+输入2+....+输入n+”-”+输入信号n
例如:
“INPUT: A-0 B-1 C-0”代表整个电路包括3个输入:A、B、C 分别输入0,1,0信号。

4)连接信息
引脚的连接信息格式:
[+输出引脚+英文空格+输入引脚1+。。。。+英文空格+输入引脚+]
例如:
[A A(8)1-1 A(8)1-3 X5-2]
代表信号从引脚A发送给与门A(8)1的1、3两个引脚,以及异或门X5的2号引脚。
[Y8-0 N1-1 O(4)2-3 Y2-1]
代表信号从引脚Y8-0发送给非门N1的1号引脚、或门O(4)2的3号引脚、同或门Y2的1号引脚。
约束条件:
一个输出引脚可以连接多个输入引脚,即将输出引脚的信号传给每一个输入引脚。但一个输入引脚不能连接多个输出引脚。
输出引脚不能短接在一起。

5)输入结束信息
所有输入以end为结束标志,end之后出现的内容忽略不计

3、程序输出
按照与门、或门、非门、异或门、同或门的顺序依次输出所有元件的输出引脚电平。同类元件按编号从小到大的顺序排序。
如果某个元件的引脚没有接有效输入,元件输出无法计算,程序输出结果忽略该元件

4、测试输入默认满足以下条件:
1)每个元件的输入引脚连续编号。假设元件有n个输入引脚,则其编号取值范围为[1,n],且引脚号不重复。
2)本题涉及的五种元件都只有一个输出引脚,输出引脚号默认为0。

实现方式

创建门、连线的类,分别存储门和电路连线的信息,再使用另一个中介类对存储的信息进行整理和计算,得到最终结果。

代码分析

以下使用SourceMomitor对代码进行分析
屏幕截图 2026-06-23 134319

屏幕截图 2026-06-23 134325
通过图片可以看出,这次作业虽然已经加上了注释,但是只占4.3%,注释太少;其次圈的复杂度过高,嵌套过深,导致代码质量下降,这是由于我没有将门按照分类分为一个个的类,将所有类型的门挤在一个Gate类中。

类图

第一次作业类图如下,其中Mai为主类,Gate类存储所有门的信息,Wire存储所有电路连线的信息,RecordValue类记录各个引脚的值,CircuitAnalyse类计算各个引脚的值。
屏幕截图 2026-06-23 133943

第二次作业

作业要求

基本同第一次作业要求,新加内容为:
1、新增门:
①、三态门:
三态门的作用类似于电路中的开关。包含一个输入引脚、一个输入控制引脚、一个输出引脚。当控制引脚为高电平时,三态门输入输出之间导通,输出电平等于输入电平;当控制引脚为低电平时,三态门输入输出之间呈现高阻态(类似开关断开),输出为无效状态。

②、译码器:
译码器的作用是讲输入的编码转换为一路有效信号。一个译码器包含两个或多个输入引脚(如图中的A2\A1\A0)、三个控制引脚(如图中的S3\S2\S1)、4个或多个输出引脚(如图中的Y7~Y0)。根据输入输出的数量有2-4线译码器、3-8线译码器等。

当控制引脚当S1 =1,S2 +S3 =0时,译码器正常工作,输出引脚只有一个输出信号0,其余输出为1;哪个引脚输出0由输入引脚的编码决定,例如:图中的3-8线译码器三个输入引脚信号的编码与输出引脚的编码对应,A2\A1\A0输入000时,Y0输出0,其余输出1;A2\A1\A0输入001时,Y1输出0,其余输出1;依次类推。
控制引脚不满足S1 =1,S2 +S3 =0时,译码器处于无效状态,所有输出为无效值。

③、数据选择器:
数据选择器的作用是从多路输入信号中选择一个,并将其信号直接送往唯一的输出端,选择哪一路输入信号由控制端决定。如图所示控制端有两个则输入端有4个,S1\S0是两个控制端,D3D0是输入端,S1\S0的4种信号组合00、01、10、11分别选择D3D0其中一路输入。如S1S0=00,则Y=D0;S1S0=01,则Y=D1;S1S0=10,则Y=D2;S1S0=11,则Y=D3
根据输入引脚数量的不同有二选一数据选择器(1个控制端)、四选一数据选择器(2个控制端)、八选一数据选择器(3个控制端)等
④、数据分配器:
数据分配器的作用与数据选择器正好相反,是将唯一的一路输入信号输出到多路输出引脚的其中之一,选择哪一路输出引脚输出由控制端决定。如图所示控制端有两个AB,输出端有4个W0\W1\W2\W3,D是输入端,AB的4种信号组合00、01、10、11分别选择W3~W0其中一路输出,其他三路输出为无效状态。如AB=00,则W0=D;AB=01,则W1=D;AB=10,则W2=D;AB=11,则W3=D。
根据输出引脚数量的不同有二路数据分配器(1个控制端)、四路数据分配器(2个控制端)、八路数据分配器(3个控制端)等
2、程序输入

1)元件信息:
用A、O、N、X、Y、S 、M、Z、F分别用作
与门、或门、非门、异或门、同或门、
三态门、译码器、数据选择器、数据分配器九种元件的元件标识符。
电路中的数据选择器、数据分配器用“标识符(控制引脚数)+编号”作为其元件名。
例如:Z(2)2代表一个四选一数据选择器,F(3)2代表一个8路数据分配器。
译码器用“标识符(输入引脚数)+编号”作为其元件名。
例如:M(3)1表示一个3-8线译码器。
2)引脚信息:
含控制引脚的元件如本次添加的所有元件,按控制-输入-输出的顺序排序,
每种类型的引脚按编号从小到大的顺序排序,
例如3-8线译码器M(3)1包含3个输入引脚、3个控制引脚、8个输出引脚,
M(3)1-0/1/2对应控制引脚S1/S2/S3,
M(3)1-3/4/5对应输入引脚A0/A1/A2,
M(3)1-6/7/8/9/10/11/12/13对应输出引脚Y0~Y7。
又如三态门的三个引脚,0号引脚为控制端、1号引脚为输入端、2号引脚为输出端。
3)电路的输入信息:
电路的输入格式:
INPUT:英文空格+输入1+”-”+输入信号1+英文空格+输入2+....+输入n+”-”+输入信号n
例如:
“INPUT: A-0 B-1 C-0”
代表整个电路包括3个输入:A、B、C 分别输入0,1,0信号。
4)连接信息
引脚的连接信息格式:
[输出引脚+英文空格+输入引脚1+。。。。+英文空格+输入引脚]
例如:
[A A(8)1-1 A(8)1-3 X5-2]
代表信号从引脚A发送给与门A(8)1的1、3两个引脚,以及异或门X5的2号引脚。
[Y8-0 N1-1 O(4)2-3 Y2-1]
代表信号从引脚Y8-0发送给非门N1的1号引脚、或门O(4)2的3号引脚、同或门Y2的1号引脚。
约束条件:
一个输出引脚可以连接多个输入引脚,即将输出引脚的信号传给每一个输入引脚。但一个输入引脚不能连接多个输出引脚。
输出引脚不能短接在一起。
3、程序输出
按照与门、或门、非门、异或门、同或门、三态门、译码器、数据选择器、数据分配器的顺序依次输出所有元件的输出引脚电平。
同类元件按编号从小到大的顺序排序。

如果某个元件的引脚没有接有效输入、输入输出之间断开(如三态门)或控制引脚输入无效,元件输出无效,程序输出忽略该元件。
#译码器不输出引脚电平,输出其输出为0的引脚的编号。如“M(3)1:3”代表译码器M3的输出引脚Y3输出0,其他引脚输出1。
#数据分配器按引脚编号从小到大的顺序输出所有输出引脚的信号,无效状态引脚输出“-”。
如“F(2)1:--0-”代表分配器F1的输出引脚W2输出0信号,其他三个引脚为无效状态。
4、测试输入默认满足以下条件:
1)每个元件的输入引脚连续编号。假设元件有n个输入引脚,则其编号取值范围为[1,n],且引脚号不重复。
2)本题涉及的五种元件都只有一个输出引脚,输出引脚号默认为0。

实现方式

按照门的分类,重新创建按9个门的类,将不同类型的门一一分开,还是将电路连线先存储起来,再统一进行计算,每计算一个,就先更新引脚的值。

代码分析

以下使用SourceMomitor对代码进行分析

屏幕截图 2026-06-23 145105

屏幕截图 2026-06-23 145122

屏幕截图 2026-06-23 145129
通过图片可以看出,这次的代码比上次有了进步,首先圈复杂度下降了,各个类型的门也分开了,且通过继承于多态提高代码的复用度;其次,虽然圈复杂度下降,但是嵌套的层数仍存在过深的问题。

类图

屏幕截图 2026-06-23 152747

第三次作业

作业要求

本次作业在第一次的作业上迭代,以下为新增要求:
1、子电路信息(本题在数字电路模拟程序-1基础上新增的内容)
可以将一部分电路设定为一个子电路,子电路可以在主电路中被引用。子电路的输入按顺序包括以下几部分:
子电路起始信息:C+子电路编号+:
子电路输入信息:
INPUT:输入1+英文空格+输入2+英文空格+....+英文空格+输入n,
子电路输出信息:
OUT:输出1+英文空格+输出2+英文空格+....+英文空格+输出n,
子电路连接信息:(格式与主电路输入信息相同),子电路的元件编号与主电路中的编号可能相同。
子电路结束标志:endc
输入、输出信息的编码可以作为子电路的引脚号在主电路中引用。
子电路元件输出时带上子电路的编号,格式为:子电路编号+“-”+元件编号+“-”+引脚号+“:”+引脚输出
例如:定义一个编号2的子电路,包含A、B两个输入和一个输出O:
C2:
INPUT:A B
OUT:C
[A X1-1]
[B X1-2]
[X1-0 Y1-1]
[A Y1-2]
[Y1-0 C]
endc
主电路中的运用:
INPUT: A-1 B-1
[A C2-A]
[B C2-B]
[C2-C N1-1]
[N1-0 OUT]
end
输出信息:
C2-X1-0:0
C2-Y1-0:0
N1-0 :1
所有子电路信息都在主电路信息之前定义完成。
2、异常输入信息(本题在数字电路模拟程序-1基础上新增的内容)
当出现各类异常输入情况时,电路应输出相应提示,异常情况包括:
①.一个连接信息中包含两个或多个输入,输出:ERROR:“连接信息”+“英文空格”+include more than one input
②.一个连接信息中没有输入信息,输出:ERROR:“连接信息”+“英文空格”+include none input
③.一个连接信息中没有输出,输出:ERROR:“连接信息”+“英文空格”+include none output
④.一个连接信息中输入输出写反,输出:ERROR:“连接信息”+“英文空格”+input and output sequence error
⑤.一个输入引脚接受中来自多个不同输出的信号,输出:ERROR:“输入引脚”+“英文空格”+input signal conflict
注:如果一条输入出现了多种异常,按以上异常先后顺序为优先级,顺序靠前者优先级越高,最后输出优先级最高的异常输出。
当电路输入信息中多条输入都包含异常,只处理排在最前面的异常信息。

实现方式

在CircuitAnalyse类中添加关于子电路的处理逻辑

代码分析

以下使用SourceMomitor对代码进行分析

屏幕截图 2026-06-23 154640

屏幕截图 2026-06-23 154645
通过图片可知,这次的代码质量相较第一次作业和第二次作业更差,首先,权复杂度过高,且是多个方法的圈复杂度都过高;其次,还是嵌套过深的问题,最大的问题在增加子电路后,我没有单独创建类来实现,而是在原CricuitAnalyse类中进行叠加函数,导致出现大问题。

类图

屏幕截图 2026-06-23 154531

关于这三次作业的学习总结

这次的作业前后迭代了三个版本,从最初的功能实现,到面向对象重构,再到新增子电路功能的扩展,最开始我抱着“能跑就行”的想法,写完了第一次作业,所以这次的代码质量不高,尤其违反了SRP原则,Gate类将所有类型的门都概括了,没有一一分开,导致代码复杂度过高;第二次的作业,我反应过来了,要将门按照类型分开,于是我创建了9个具体的类,还有一个Gate父类,通过继承与多态,降低代码的复杂度,提高代码质量,但是这次很遗憾没有百分百通过所有测试点;第三次作业,要求在第一次的代码上进行迭代,由于不想重新开始,于是没有将门按照类型分开,全部堆在一个Gate类中,也没有给新增的子电路重新创建新的类,而是在原来的代码基础上继续堆新的方法,导致代码质量大幅下降,复杂度再次变高。
但是在这次作业中,我也有了新的认识,以前总觉得 “继承、多态” 是应付考试的知识点,直到这次作业一到作业二的重构,才真切感受到它的实际价值。在第三次作业中,功能很快就做出来了,最高圈复杂度从 12 涨到了 18,主方法 main() 成了新的 “重灾区”,最大嵌套深度从 5 层涨到了 7 层,深层嵌套的语句数量明显增加,之前已经解决的 calculateOutput() 高复杂度问题,又回来了,当时图快省下来的时间,但是后面都加倍还回去了。代码越堆越乱,陷入 “越写越慢、越改越错” 的恶性循环,以至于最后没有百分比完成,只得到83分,甚至出现了非零返回。至此,我认识到写代码不能偷懒,若为了一时之快,将来指挥更加麻烦,代码质量只会越来越差。

此次作业的踩坑经验

1、在进行计算时,不能一边计算一边存储电路信息,这样会导致崩溃或只能输出一个输出引脚的值;
2、写代码不能偷懒,要重构时一定要进行重构,不能怕麻烦就不做,不然会越来越麻烦;
3、当种类太多时,可以采用继承与多态,避免使用switch和if else,降低代码的复杂度。

posted @ 2026-06-23 16:28  吴以轩  阅读(4)  评论(0)    收藏  举报