继承与多态OOP作业总结
前言
第二次作业集相比第一次作业集来说难度上大了好多,做的过程非常煎熬。也有好多不会的,总结下来学到了一些java的核心设计模式和关键算法设计:
-
继承技术的使用
-
多态的使用
-
SRP,OCP,DIP等设计原则的使用
-
使用正则表达式处理字符串
-
模块化设计
设计与分析
第一次作业
要求如下:
请编程实现数字电路模拟程序,
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。
类图如下:

通过类图分析得知:
运用继承,CircuitElement定义通用的接口,各个门类继承此原件类,使代码具有复用性和多态性。
子类通过重写父类计算结果方法输出结果
但是在写代码时发现一个比较大的问题,因为数据会被初始化为0,如果没有输出的话,系统还是会给此元件输出一个低电平。所以我在每一个引脚类上加上了一个是否准备好的属性,在每一个元件计算的时候判断引脚有没有准备好再开始计算结果。
在此次题目我花最多时间的是输入输出的处理,在经过很多次非零返回后,使用正则表达式处理字符串解决问题。
复杂度分析:

经分析:
Main方法Max Complexity=36、Avg Complexity=36,远超 20 的严重阈值;单一 main 方法圈复杂度极高,分支、判断逻辑堆叠。
解决方法为将 main 中业务逻辑拆分多个独立小方法(初始化、电路构建、仿真计算、打印输出等分模块);
抽取重复分支逻辑为工具方法,减少 if 嵌套,用多态 / 枚举替代大量条件判断;
第二次作业
添加
三态门:
三态门的作用类似于电路中的开关。包含一个输入引脚、一个输入控制引脚、一个输出引脚。当控制引脚为高电平时,三态门输入输出之间导通,输出电平等于输入电平;当控制引脚为低电平时,三态门输入输出之间呈现高阻态(类似开关断开),输出为无效状态。
译码器:
译码器的作用是讲输入的编码转换为一路有效信号。一个译码器包含两个或多个输入引脚(如图中的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、程序输入
元件信息:
用A、O、N、X、Y、S 、M、Z、F分别用作
与门、或门、非门、异或门、同或门、
三态门、译码器、数据选择器、数据分配器九种元件的元件标识符。
电路中的每个与门、或门用“标识符(输入引脚数)+编号”作为其元件名。
例如:A(8)1表示一个8输入引脚的与门,O(4)2代表一个4输入引脚的或门。
电路中的每个非门、异或门、同或门用“标识符+编号”作为其元件名。
例如:X8表示一个异或门,Y4代表一个同或门,N1代表一个非门。
电路中的数据选择器、数据分配器用“标识符(控制引脚数)+编号”作为其元件名。
例如:Z(2)2代表一个四选一数据选择器,F(3)2代表一个8路数据分配器。
译码器用“标识符(输入引脚数)+编号”作为其元件名。
例如:M(3)1表示一个3-8线译码器。
约束条件:
不同元件的编号可以相同,如X4、Y4。
同一电路中同种元件的编号不可重复,可以不连续
引脚信息:
引脚信息由“元件名-引脚号”构成。
例如:A(8)1-2代表与门A(8)1的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号引脚为输出端。
电路的输入信息:
电路的输入格式:
INPUT:英文空格+输入1+”-”+输入信号1+英文空格+输入2+....+输入n+”-”+输入信号n
例如:
“INPUT: A-0 B-1 C-0”
代表整个电路包括3个输入:A、B、C 分别输入0,1,0信号。
连接信息
引脚的连接信息格式:
[输出引脚+英文空格+输入引脚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号引脚。
约束条件:
一个输出引脚可以连接多个输入引脚,即将输出引脚的信号传给每一个输入引脚。但一个输入引脚不能连接多个输出引脚。
输出引脚不能短接在一起。
输入结束信息
所有输入以end为结束标志,end之后出现的内容忽略不计
3、程序输出
按照与门、或门、非门、异或门、同或门、三态门、译码器、数据选择器、数据分配器的顺序依次输出所有元件的输出引脚电平。
同类元件按编号从小到大的顺序排序。
如果某个元件的引脚没有接有效输入、输入输出之间断开(如三态门)或控制引脚输入无效,元件输出无效,程序输出忽略该元件。
译码器不输出引脚电平,输出其输出为0的引脚的编号。如“M(3)1:3”代表译码器M3的输出引脚Y3输出0,其他引脚输出1。
数据分配器按引脚编号从小到大的顺序输出所有输出引脚的信号,无效状态引脚输出“-”。
如“F(2)1:--0-”代表分配器F1的输出引脚W2输出0信号,其他三个引脚为无效状态。
4、测试输入默认满足以下条件:
1)每个元件的输入引脚连续编号。假设元件有n个输入引脚,则其编号取值范围为[1,n],且引脚号不重复。
2)本题涉及的五种元件都只有一个输出引脚,输出引脚号默认为0。
类图如下:


Input、Connection、Pin、InputPin、OutputPin,负责存储输入信号、连线关系、引脚状态与电平。
抽象父类 CircuitElement,统一所有电路元件的生命周期行为(输入校验、计算、引脚赋值、输出打印)。
AndGate、OrGate、NotGate、XorGate、Decoder、Mux、Demux 等,各自实现独立的 calculate() 逻辑。
Agent 工具类负责字符串解析、器件工厂创建、元件查找与排序;
Main 主类负责输入解析与结果输出。
Agent 类封装 createElement 工厂方法,根据器件名称前缀自动匹配并实例化对应电路元件,实现配置驱动创建对象,解耦业务与对象创建逻辑。
针对译码器、分路器等特殊器件重写 printOutput 方法,实现个性化输出格式,普通门电路统一通用输出。
复杂度分析:

分析出:
器件判断、引脚偏移、类型判断大量 if-else 硬编码,未使用枚举或常量封装。
解决方法为:
引入枚举管理器件类型:消除大量 if-else 判断,提升扩展性。
第三次作业
加上:
子电路信息(本题在数字电路模拟程序-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
所有子电路信息都在主电路信息之前定义完成。
异常输入信息(本题在数字电路模拟程序-1基础上新增的内容)
当出现各类异常输入情况时,电路应输出相应提示,异常情况包括:
1.一个连接信息中包含两个或多个输入,输出:ERROR:“连接信息”+“英文空格”+include more than one input
例如:
INPUT: A-1 B-1
[A B A2-1]
应输出:
ERROR: [A B A2-1] include more than one input
2.一个连接信息中没有输入信息,输出:ERROR:“连接信息”+“英文空格”+include none input
例如:
INPUT: A-1 B-1
[C1-1 C2-1]
应输出:
ERROR: [C1-1 C2-1] include none input
注意:C1-1 C2-1引脚是元件的输入引脚,但作为连接信息,元件的输入引脚属于连接系统的输出,所以是none input
3.一个连接信息中没有输出,输出:ERROR:“连接信息”+“英文空格”+include none output
例如:
INPUT: A-1 B-1
[A]
应输出:ERROR: [A] include none output
4.一个连接信息中输入输出写反,输出:ERROR:“连接信息”+“英文空格”+input and output sequence error
例如:
INPUT: A-1 B-1
[A2-1 A]
应输出:ERROR: [A2-1 A] input and output sequence error
5.一个输入引脚接受中来自多个不同输出的信号,输出:ERROR:“输入引脚”+“英文空格”+input signal conflict
例如:
INPUT: A-1 B-1
[A A2-1]
[B A2-1]
应输出:ERROR: A2-1 input signal conflict
注:如果一条输入出现了多种异常,按以上异常先后顺序为优先级,顺序靠前者优先级越高,最后输出优先级最高的异常输出。
当电路输入信息中多条输入都包含异常,只处理排在最前面的异常信息。
输入结束信息
所有输入以end为结束标志,end之后出现的内容忽略不计
3、程序输出
按照与门、或门、非门、异或门、同或门的顺序依次输出所有元件的输出引脚电平。同类元件按编号从小到大的顺序排序。
如果某个元件的引脚没有接有效输入,元件输出无法计算,程序输出结果忽略该元件
4、测试输入默认满足以下条件:
1)每个元件的输入引脚连续编号。假设元件有n个输入引脚,则其编号取值范围为[1,n],且引脚号不重复。
2)本题涉及的五种元件都只有一个输出引脚,输出引脚号默认为0。
类图如下:


用PinUtils 工具类,封装所有字符串解析、引脚格式校验、器件编号提取、子电路标识解析等通用能力,消除全局重复代码
使用InputParser 解析器,独立承担所有文本输入解析工作,区分主电路、子电路、输入信号、连线拓扑,结构化封装为统一数据对象。
使用工厂模式根据器件标识自动实例化对应门电路对象,绑定子电路归属、器件编号,完成电路拓扑实例搭建。
用OutputFormatter 输出工具类,专注器件排序、名称格式化、结果标准化打印,统一输出规范。
遍历所有主电路与子电路连线,自动识别所有门电路器件,通过工厂方法创建对应器件实例,标记器件所属子电路ID、编号、名称。
复杂度分析

通过分析:
PinUtils 工具类的格式校验仅做基础判断,存在多处边界漏洞:未校验空引脚编号、非法字符、重复定义、重复连线、子电路ID重复、器件名称格式异常等场景;对于不规范输入只会直接忽略或静默失败,不会精准提示具体错误位置。
器件引脚使用双Map(inputValues、inputSet)分开存储状态,虽然灵活,但存在状态不一致风险(出现值已赋值但标记未更新、标记已更新但值为空的脏数据);全局信号表、子电路信号、器件输出信号分散存储,数据统一性较差。、
主电路、子电路信号传播逻辑高度相似,但未抽取公共方法,写了两套独立传播逻辑
总结
通过本次数字电路仿真程序的开发与重构,我主要学到了很多实用的编程与工程开发知识。首先我理解了面向对象分层设计的意义,不再把所有代码堆在一个主方法里,学会按解析、构建、校验、运算、输出拆分功能,让代码结构清晰、方便修改和排查问题。其次我掌握了字符串解析、数据封装、状态管理等基础编程能力,能够读取并识别自定义格式的电路文本,完成数据提取和逻辑处理。同时我也学会了仿真程序的核心思路,通过循环迭代、信号传播实现电路稳态计算,理解了数字门电路的工作逻辑与子电路嵌套的设计思想。在代码优化过程中,我深刻体会到规范编码、减少嵌套、解耦分工的重要性,认识到功能能跑不代表代码合格,低复杂度、易维护、高容错的代码才是标准的工程代码。最后我也发现了自己在异常处理、边界校验、代码复用方面的不足,为后续写出更规范、更稳定的程序积累了宝贵的经验。
浙公网安备 33010602011771号