作业集04~06总结性Blog

一、前言
本阶段作业集04~06围绕“NCHUD数字电路模拟程序”的迭代开发展开。三次作业虽然题目数量都只有一道主编程题,但每一道题的代码量和设计要求都比较高。作业集04主要完成基础逻辑门模拟,要求处理与门、或门、非门、异或门、同或门五种基础元件;作业集05在此基础上加入三态门、译码器、数据选择器和数据分配器,程序需要支持控制引脚、多输出引脚和无效状态;作业集06进一步加入子电路和异常输入检测,使程序从单层电路计算扩展到组合结构建模。
从提交结果看,作业集04取得100分,说明基础逻辑门、电平传播和排序输出等核心功能基本稳定。作业集05只取得49分,说明复杂元件扩展时原有设计没有完全支撑新增需求,特别是控制引脚编号、数据分配器输出顺序和无效状态处理等方面存在问题。作业集06取得93分,说明子电路和异常检测主体功能基本完成,但在多子电路或复杂嵌套场景中仍有遗漏。

屏幕截图 2026-06-24 151906

屏幕截图 2026-06-24 151848

屏幕截图 2026-06-24 151824

二、设计与分析
2.1 作业集04:基础逻辑门模拟
作业集04的源码使用了一个内部类Gate来表示元件。该类保存了元件类型、编号、输入引脚数量、输入值数组、输出值和是否已计算等状态。程序读取输入后,先从连接信息中收集源引脚和目标引脚,再根据引脚名称反向创建对应的门元件,最后使用队列传播信号。
这一版本的优点是结构直接,基础逻辑门的计算集中在calc()方法中,便于快速实现。与门和或门通过遍历输入数组完成多输入计算,非门、异或门和同或门则按照固定输入数量计算。程序还通过ready()判断输入是否全部有效,避免在引脚未接通时提前输出。
不过,这种设计也埋下了后续扩展的问题。所有逻辑都集中在一个Gate类中,元件类型依赖字符串判断。如果新增三态门、译码器或数据分配器,继续在calc()中增加分支,会导致方法越来越长,也会让不同元件的引脚规则混在一起。

2.2 作业集05:复杂元件扩展
作业集05的源码开始引入抽象类Component,并为不同元件建立子类,例如AndGate、OrGate、NotGate、XorGate、XnorGate、TriStateGate、Decoder、Multiplexer和Demultiplexer。相比作业集04,这一版本的类设计更接近面向对象思路,每种元件都有自己的canCalculate()、calculate()和print()方法。
从结构上看,这次作业已经意识到不同元件需要不同计算规则。例如三态门在控制端为1时才输出,译码器需要根据控制端和输入编码确定某一路输出为0,数据选择器根据控制端选择一路输入,数据分配器则根据控制端决定哪一路输出有效。这些元件和基础逻辑门相比,引脚含义明显更复杂。
失分较多的原因主要集中在复杂元件细节上。第一,控制端和输入端的编号规则容易写错。第二,数据分配器题目要求按输出引脚编号从小到大输出,并用“-”表示无效状态,如果把选择顺序理解反,就会导致隐藏测试点错误。第三,三态门和数据分配器中的无效状态不能简单当作0处理,否则会改变电路含义。第四,译码器的输出格式不是普通“引脚:电平”,而是输出为0的引脚编号,这也容易与普通元件输出格式混淆。

2.3 作业集06:子电路与异常检测
作业集06的源码引入了Conn、Circuit和EvalResult三个内部类。Conn用于保存一条连接信息的原始字符串、拆分后的token、源端和目标端;Circuit用于保存一个电路或子电路的输入、输出、连接关系和输入值;EvalResult用于保存计算结果和输出行。
这一版本的核心变化是将子电路作为独立电路对象处理。程序先读取所有子电路定义,再读取主电路。计算时,主电路可以通过C2-A、C2-B这样的形式向子电路输入信号,也可以通过C2-C读取子电路输出。源码中的eval()方法承担了递归计算的作用:当某个子电路输入齐全后,就调用eval(sub, in, prefix + childId + "-")计算子电路内部结果,并把子电路输出映射回主电路。
异常检测由validateAll()完成。程序在真正求值之前先检查连接信息,按题目要求判断是否存在多个输入源、没有输入源、没有输出端、输入输出顺序错误以及输入引脚信号冲突。这个设计比较合理,因为异常连接如果先进入计算流程,会使后续结果失真。
作业集06取得93分,说明整体框架是有效的。但从成绩截图看,仍然存在一个复杂测试点未通过,提示为“多子电路”。结合源码结构分析,可能问题出在多子电路场景下的命名空间隔离、输出顺序或递归求值时机。当前程序使用子电路编号作为前缀区分输出,但如果多个子电路之间存在交叉依赖,或者子电路输出需要再次驱动主电路中的其他连接,求值循环的触发条件就需要更加严谨。

image
image

三、采坑心得
3.1 只看当前题目,导致后续扩展困难
作业集04取得满分时,我以为基础模型已经比较稳定。但到了作业集05,三态门、译码器、数据选择器和数据分配器加入后,才发现原先“一个Gate类 + type判断”的设计扩展性不足。基础逻辑门都只有一个输出引脚,而且输入输出规则比较统一;复杂元件则存在控制端、多输出和无效状态,继续用统一分支处理会让代码越来越难维护。
3.2 无效状态没有单独建模
作业集05中,无效状态是一个重要概念。三态门控制端为0时输出无效,数据分配器未被选中的输出也为无效。如果程序内部只使用0和1表示电平,就很容易把无效状态误判为低电平。比较合理的做法是使用-1或null表示无效,并在输出阶段再转换成题目要求的“-”。
3.3 输出格式和计算格式混在一起
不同元件的输出格式并不完全相同。普通逻辑门输出元件-0:值,译码器输出元件:编号,数据分配器输出一串包含0、1和“-”的状态。如果计算逻辑和打印逻辑没有分开,就容易在修改一种元件时影响其他元件。作业集05源码中虽然给每个Component设计了print()方法,但部分输出规则仍然需要更细致处理。
3.4 子电路不是简单字符串前缀
作业集06让我体会到,子电路不能只当作普通元件名处理。子电路内部有自己的输入、输出、连接和元件编号,甚至可能与主电路编号重复。如果只是给输出加前缀,而没有在数据结构上隔离不同电路,就容易在多子电路或嵌套场景中出现信号混淆。
image

四、改进建议
第一,应进一步统一元件抽象。可以定义一个抽象类或接口Component,要求所有元件实现canCalculate()、calculate()和getOutputs()。这样普通逻辑门、复杂元件和子电路都可以放在统一框架中处理。
第二,应把引脚类型显式建模。不要只用字符串和编号判断引脚含义,而是给每个元件维护控制引脚、输入引脚和输出引脚列表。这样可以减少输入输出顺序错误,也方便异常检测。
第三,应将异常检测模块独立出来。异常检测不应该散落在计算流程中,而应在构建连接关系之前完成,并严格按照题目优先级处理。
第四,应加强测试用例设计。除了题目样例,还应专门测试三类数据:边界输入、异常输入和复杂组合输入。例如多子电路同时存在、同一输入引脚被重复连接、三态门断开、数据分配器不同选择端组合等。

五、总结
通过作业集04~06,我对面向对象设计和迭代开发有了更具体的认识。作业集04让我熟悉了基础逻辑门的建模和信号传播;作业集05让我看到复杂元件加入后,类设计和状态表达会直接影响程序正确性;作业集06则让我进一步理解了子电路、异常检测和组合模式的意义。
这三次作业中,我最大的收获不是某一个具体语法点,而是认识到程序结构会影响后续扩展。一个在当前题目中能通过的方案,不一定适合后续迭代。如果类职责不清、输入解析和计算逻辑混在一起,那么需求一复杂,代码就会迅速变得难以维护。
后续我需要继续加强三个方面:第一,学习更规范的面向对象建模方法;第二,提高对边界测试和异常测试的重视;第三,在写代码前先分析可能的迭代方向,避免只为当前测试点写临时性代码。

posted @ 2026-06-24 15:31  唐梓轩  阅读(3)  评论(0)    收藏  举报