OOP第二阶段PTA4~6次作业总结
我的私人博客:https://www.chzxqwdslx.com/
作业集4~6总结:数字电路模拟系统三次迭代的设计、度量与反思
一、前言:三次作业集的知识点、题量与难度概览
本阶段三次 PTA 作业围绕"数字电路模拟"这一计算机底层核心场景展开,每次迭代都在前一版基础上引入了更贴近工程实践的约束。从学习价值上看,这三次作业并不只是在写若干个类,更重要的是强制我们用面向对象的方式拆分职责、明确类关系,理解组合模式的应用。
- 作业集4:基础数字电路模拟;实现五种基本逻辑门(与门、或门、非门、异或门、同或门);强调继承体系与多态;处理电路连接与信号传播。
- 作业集5:扩展元件类型;新增三态门、译码器、数据选择器、数据分配器四种复杂元件;引入控制引脚概念;需要处理多输出引脚元件。
- 作业集6:子电路支持与异常处理;引入子电路定义机制(组合模式);实现嵌套子电路解析;增加多种异常输入检测与错误提示。
题量方面,三次作业均为单题,但单题内部包含较多子功能;难点不是Java语法,而是理解数字电路原理与满足测试要求。尤其是V6的子电路嵌套解析与异常处理。
二、设计与分析
2.1 V4:基础数字电路模拟
2.1.1 需求拆分与职责划分
V4 的业务目标很清晰:录入电路连接信息,模拟信号传播,输出各元件的输出引脚电平:
- LogicGate:抽象基类,定义门元件的基本属性(名称、前级门列表、输出电压)和抽象计算方法。
- ANDGate/ORGate/NOTGate/XORGate/XNORGate:具体门类,继承LogicGate,实现各自的逻辑运算。
- INGate/OUTGate:输入输出门,用于处理电路边界信号。
- CircuitSimulator:电路模拟器,负责解析输入、管理元件、执行模拟、输出结果。
- Main:流程编排(读取输入 → 构造电路 → 模拟 → 输出),不承载业务细节。
2.1.2 类关系
V4 的核心关系较简单:
- LogicGate 与各具体门类:继承关系(多态)。
- LogicGate 与 LogicGate:聚合(每个门持有前级门列表)。
- CircuitSimulator 与 LogicGate:关联(模拟器管理所有门元件)。

2.1.3 关键流程与算法分析
整体流程可以抽象为:
- 读取INPUT行,解析输入信号并创建输入门。
- 读取连接信息行,解析引脚连接关系。
- 根据连接关系构建门元件之间的依赖关系。
- 执行模拟:递归计算每个门的输出(从输入门开始传播)。
- 按类型和编号排序输出结果。
核心算法是递归信号传播:每个门在计算输出时,先递归计算所有前级门的输出,然后根据自身逻辑运算得出结果。
2.1.4 SourceMonitor 度量与结论

结合代码结构,我对 V4 的度量结论是:
- 规模:类数量适中,继承体系清晰,便于后续扩展新元件类型。
- 复杂度热点:CircuitSimulator的parseGateName方法包含多个条件分支,可考虑重构。
- 可维护性:继承体系使得添加新门类型只需新增一个子类,符合OCP。
2.2 V5:扩展元件类型
2.2.1 需求增量分析
V5 在 V4 基础上引入了四个关键增量:
- 三态门:包含控制引脚,当控制为低电平时输出高阻态(无效状态)。
- 译码器:多输入多输出元件,根据控制信号决定哪个输出为低电平。
- 数据选择器:根据控制信号选择一路输入信号输出。
- 数据分配器:将输入信号分配到由控制信号指定的输出引脚。
这意味着系统需要同时处理:
- 控制引脚与数据引脚的区分。
- 多输出引脚元件的输出格式。
- 无效状态(高阻态)的处理。
2.2.2 类职责与关系分析
按提交源码统计,V5 共 15 个类。相较 V4,核心变化在于引入四种新元件:
- TSGate:三态门,控制引脚决定是否导通。
- DecoderGate:译码器,支持2-4线、3-8线等多种规格。
- MultiplexerGate:数据选择器,根据控制选择输入。
- DemultiplexerGate:数据分配器,根据控制分配输出。
类关系上:
- 四种新元件均继承LogicGate。
- DecoderGate和DemultiplexerGate需要维护多个输出引脚的状态。
- CircuitSimulator需要扩展parseGateName以识别新元件。

2.2.3 控制引脚处理流程
从工程视角看,这里开始出现"引脚顺序"与"状态判断":
- 含控制引脚的元件按控制-输入-输出的顺序编号。
- 译码器输出为低电平的引脚编号,而非电平值。
- 数据分配器输出所有引脚状态,无效状态用"-"表示。
2.2.4 SourceMonitor 度量与结论

结合 V5 的结构,我对度量结果的解读重点是:
- 复杂度应集中在新元件的计算方法。
- 输出格式化逻辑需要区分不同元件类型。
- 引脚连接处理需要考虑位置索引。
2.3 V6:子电路支持与异常处理
2.3.1 需求增量:从"单电路"到"模块化"
V6 的核心从"单一电路模拟"升级到"支持子电路模块化设计"。它引入了:
- 子电路定义:可以将一部分电路设定为一个子电路,在主电路中引用。
- 嵌套子电路:子电路内部可以再定义子电路。
- 异常检测:检测多种输入错误并输出相应提示。
异常类型包括:
- 连接信息包含多个输入。
- 连接信息没有输入。
- 连接信息没有输出。
- 输入输出顺序错误。
- 输入引脚信号冲突。
2.3.2 模型设计:组合模式应用
题目明确建议采用组合模式,将子电路和电路元件作为抽象元件类的子类:
- Gate:门元件类,记录元件名称、类型、输入输出引脚。
- GateType:枚举类,定义五种门类型。
- SubCircuit:子电路定义类,包含输入输出引脚集合。
- Parser:解析器类,负责解析输入格式、识别子电路定义。
- Simulator:模拟器类,采用BFS算法执行信号传播。
- Connection:连接信息类,定义引脚类型和连接行结构。
- OutputFormatter:输出格式化类,统一处理输出格式。

2.3.3 解析与模拟算法分析
V6采用全新的解析与模拟架构:
解析阶段:
- 识别子电路定义(C编号:开头,endc结束)。
- 解析主电路输入信息。
- 解析所有连接信息,按顺序存储。
- 对每个连接行进行引脚分类和异常检测。
模拟阶段:
- 初始化所有主电路输入信号,加入队列。
- 维护每个门元件的输入引脚值映射。
- 从队列取出信号源,传播到所有目标引脚。
- 当门的所有输入都有值时,计算输出并加入队列。
2.3.4 SourceMonitor 度量与结论

V6 的度量重点应放在:
- Parser类的复杂度:子电路解析涉及多层嵌套。
- 异常检测逻辑:五种异常需要按优先级处理。
- 模块化程度:解析、模拟、输出分离,符合SRP。
三、采坑心得
3.1 V4排序问题
V4中有一个输出排序的测试点一直过不去。我自己对特殊情况进行了测试,一直过不了,不知道怎么突然想到不会有多个输入吧,然后我试了试多个输入我原本的程序果然处理异常,改进代码后,终于成功通过了测试点。
3.2 V5引脚连接问题
这个我的思路是把新增的元件拆成多个逻辑门,可能我这里就有点接近组合模式了,可是我无论如何都处理不好,因为对应的是动态变化的,从后递归往前也出现了问题。
3.3 V6异常优先级问题
V6要求对多种异常进行检测,并且有优先级顺序。一开始我把所有异常检测写在一起,发现无法正确处理优先级。后来我按照题目要求的顺序,先检测"多个输入",再检测"无输入",再检测"无输出",再检测"顺序错误",最后检测"信号冲突",每种异常检测后立即返回,不再继续检测后续异常。还有题目没有明说对子电路也要进行排序,经过多次尝试后,尝试出来了。
3.4 V6子电路嵌套解析
V6的子电路支持嵌套定义,解析时需要正确处理作用域。一开始我用简单的线性解析,发现无法正确识别嵌套子电路。后来我采用递归解析方法,在遇到子电路起始标记时递归调用解析函数,直到遇到endc才返回,成功解决了嵌套问题。
四、改进建议
4.1 架构改进
建议将门元件的创建逻辑从CircuitSimulator中分离出来,使用工厂模式或策略模式,使得添加新元件类型时只需新增一个类,无需修改模拟器代码。
4.2 异常处理改进
建议将异常检测逻辑封装成独立的Validator类,每种异常对应一个检测方法,便于扩展新的异常类型。
4.3 输出格式改进
建议使用策略模式处理不同元件类型的输出格式,每种元件对应一个输出策略,避免在printResults中使用大量if-else分支。
五、总结
本阶段三次作业让我对面向对象设计有了更深入的理解:
在 V4 中,我第一次构建完整的继承体系,体会到多态对代码复用与扩展的直接提升。
在 V5 中,我学会了处理复杂元件的多引脚、多输出问题,理解了控制信号与数据信号的区分。
在 V6 中,我真正应用了组合模式,理解了模块化设计的价值;同时学会了异常处理的优先级策略。
建议
- 测试用例希望更加丰富,帮助我们更好地理解题目要求。
- 题目中对子电路的输出格式说明可以更加详细,避免理解歧义。
- 希望提供更多关于数字电路原理的背景知识,帮助理解元件功能。
