作业集4-6 Blog作业
数字电路模拟程序 1~3 三次迭代作业总结博客
一、前言
这次连续完成数字电路模拟程序 1、2、3 三个迭代版本,难度逐步递增,功能持续叠加,完整走完一套软件从简易功能到完善架构的开发全过程。
简单概括三个版本各自的核心任务:
- 程序 1 是基础入门版本,仅实现五种基础逻辑门:与门、或门、非门、异或门、同或门。主要练习字符串解析、面向对象封装门电路,完成基础电路信号传递仿真。
- 程序 2 大幅提升难度,新增三态门、译码器、数据选择器、数据分配器,新增控制引脚概念,引脚分为控制引脚、数据输入引脚、输出引脚三类,各类元件输出格式各不相同,运算逻辑复杂度大幅提高。
- 程序 3 属于完整重构升级版,新增子电路功能,采用组合设计模式开发;同时增加全套输入异常检测,遇到非法连接、引脚信号冲突时会按照固定优先级打印错误信息并终止程序,程序健壮性大幅提升。
完成三套作业后,我积累了大量实用开发能力:熟练使用正则表达式解析各类自定义格式的元件、引脚文本;吃透组合设计模式,统一管理独立门元件和封装好的子电路;掌握数字电路信号迭代仿真逻辑;学会分层拆分代码,将解析、运算、报错、输出模块完全解耦;同时养成提前处理非法输入的开发习惯。
下文结合 类图、SourceMonitor 代码检测报表、调试过程中遇到的各类 bug、仿真流程图,分版本讲解代码设计思路、踩坑复盘、可优化方向,最后对整个阶段学习做综合总结。
二、三次作业设计与代码分析
(一)第四次作业:数字电路模拟程序 1
1. 作业需求梳理
仅支持五种基础逻辑门:与门、或门可自定义多路输入引脚;非门仅 1 路输入;异或门、同或门固定 2 路输入;所有门输出引脚编号统一为 0。
输入内容分为全局电路输入信号、多条[]包裹的引脚连接语句,读取到 end 标识即结束输入。硬性规则:单个元件输入引脚只能接收一路信号,不允许多路信号同时接入同一引脚。
输出要求按照与门、或门、非门、异或门、同或门的顺序打印,同类型元件按编号从小到大排序;若某个逻辑门缺少完整输入信号、无法计算输出电平,则直接跳过该元件,不进行输出。
2. 代码分层实现思路
整套代码拆分为四层,各司其职,避免所有逻辑堆积在 main 主函数:
- 实体存储层:定义逻辑门抽象父类,五种基础门全部继承该父类,每种门单独重写输出电平计算方法;单独创建实体类存储每一个引脚的电平数值、信号来源。
- 解析工具层:独立工具类,使用正则拆分不同格式的元件名(例如A(2)1、X5),切割 INPUT 全局信号,解析中括号内的引脚连接关系,记录信号流向映射表。
- 仿真调度层:主电路类统一管理所有逻辑门、全局输入信号,循环更新全部门电路输出电平,直到所有引脚电平不再发生变化,判定电路仿真稳定。
- 程序入口层:仅负责逐行读取控制台输入,调用解析、仿真工具,仿真结束后按照规定规则排序输出结果。
3. 类图

4. SourceMonitor 代码度量报表数据

5. 开发过程 bug 复盘
- 元件名字符串解析正则设计存在漏洞,无法区分带括号的与 / 或门和无括号的异或、同或、非门,无法提取多路输入门的引脚数量,后续拆分两套独立正则分别匹配两类元件才修复问题。
- 初次仿真仅单次遍历更新信号,无法处理多级串联电路。例如与门输出接入非门输入时,非门会读取上一轮旧电平,仿真结果完全错误;修改为循环迭代更新电平,连续两次遍历电平无变化时停止仿真,所有用例运行正常。
- 缺少引脚完整性校验逻辑,异或门只接入一路输入时仍强制运算,输出结果错乱;新增判断逻辑,若元件规定输入引脚未全部接入有效信号,标记元件失效,输出阶段直接忽略。
(二)第五次作业:数字电路模拟程序 2
1. 版本新增难点
新增四类全新电路元件,引入控制引脚概念,引脚严格分为控制引脚、数据输入引脚、输出引脚三类,引脚编号顺序固定不可打乱。
各类元件输出规则差异极大:译码器仅输出低电平对应的引脚编号;数据分配器输出由 0、1、- 拼接而成的字符串;三态门控制引脚为低电平时直接断开,元件失效不输出;整体输出排序序列新增四类元件,排序规则更新。
2. 代码核心改动点
- 升级门抽象父类,新增三组集合分别存储控制引脚、数据输入引脚、输出引脚,替换原版单一输入列表;新增三态门、译码器、数据选择器、数据分配器四个子类,各自重写电平计算逻辑和格式化输出方法。
- 解析工具全面升级,可识别九类元件标识符,自动匹配每种元件对应的引脚编号区间,不会混淆控制引脚与数据输入引脚。
- 新增信号状态枚举类,区分高电平 1、低电平 0、高阻无效三种状态,方便标记三态门断开、译码器未使能等失效场景。
3.类图

4. SourceMonitor 代码度量报表数据

5. 开发过程 bug 复盘
- 三态门控制逻辑写反,控制引脚高电平断开、低电平导通,全部测试样例输出完全颠倒;分步打印控制引脚电平,逐行核对逻辑后修正。
- 译码器未前置校验控制引脚使能条件,S1=1、S2+S3=0 不满足时依旧正常计算输出;新增前置判断,未达到使能条件直接标记全部输出引脚无效。
- 数据分配器输出字符串遍历顺序错误,未按照引脚编号从小到大拼接,输出格式与题目样例不符。
- 解析逻辑混淆控制引脚和数据输入引脚,信号读取错位;后续根据元件类型固定引脚分段区间,彻底解决引脚分类错乱问题。
(三)第六次作业:数字电路模拟程序 3
1. 两大核心新增功能
- 支持子电路封装复用:可将一段完整电路打包为子电路,拥有独立输入、输出端口,主电路可直接调用子电路端口;子电路内部元件编号可与主电路重复,输出时必须携带子电路编号前缀区分。
- 完整输入异常检测机制:共五类错误,存在严格优先级;单条连接语句同时触发多个错误时,仅输出优先级最高的报错;多条连接语句存在异常时,仅处理第一条异常并直接终止程序运行。
2. 架构重构
- 顶层抽取统一抽象电路单元父类,单个逻辑门、完整子电路都属于电路单元,共用一套仿真运算、遍历输出接口。
- 分为两类子类:叶子单元对应九种基础门;容器单元对应子电路,内部可装载任意电路单元,自带独立输入、输出端口映射表。
- 新增独立异常校验工具类,严格按照题目给定优先级顺序校验每条连接语句,捕获错误后立刻打印提示并结束程序。
- 解析器新增子电路识别状态,读取Cx:标识后切换子电路解析模式,读取 endc 结束标记后切回主电路模式;子电路内部信号域与主电路完全隔离,互不干扰。
3.类图

4. SourceMonitor 代码度量报表数据

5. 开发过程 bug 复盘
- 子电路端口信号无法同步:主电路向C1-A端口传入电平后,子电路内部 A 端口电平无变化;新增双向端口映射表,仿真阶段同步内外端口电平。
- 异常判断顺序颠倒,先检测引脚冲突再检测多路输出源,单条语句会同时打印多条错误,不符合样例输出要求;严格按照题目 1~5 优先级顺序判断,命中任意错误直接终止当前语句校验。
- 子电路与主电路元件编号重复,输出无法区分归属;格式化输出时强制拼接Cx-前缀,区分不同层级电路元件。
- 无法区分连接语句内信号源与接收引脚,经常顺序颠倒;固定规则:中括号内第一个元素为输出信号源,剩余所有元素均为接收信号的输入引脚。
三、采坑心得
- 自定义文本解析是全程最容易出错的模块
最开始不会使用正则表达式,依靠多层 if 判断拆分元件名,代码冗长且极易遗漏分支,代码度量圈复杂度居高不下。改用正则分组捕获后,解析代码精简一半,逻辑清晰稳定。
子电路属于多行分段读取内容,未设置解析状态标记时,极易混淆主电路、子电路文本;新增解析状态枚举,切换子电路模式时单独缓存文本,隔离处理后不再出现内容错乱。
- 电路信号仿真逻辑不能凭主观想象编写
最初仅单次遍历更新引脚电平,多级串联电路全部计算错误;修改为循环迭代更新电平,连续两次遍历无电平变化时判定仿真收敛,所有测试用例才能正常运行。
带有控制引脚的元件必须优先校验控制端状态,再计算数据输出;若先运算数据再判断控制开关状态,会出现开关断开依旧输出有效电平的 bug。
- 初期未理解组合模式,代码重复冗余严重
最开始将子电路设计为独立复刻主电路全部逻辑的类,重复代码占比极高,复用率极低。重构组合模式后,独立门和子电路共用一套仿真、遍历逻辑,无需重复开发相同功能,代码复用率大幅提升。
从中总结经验:只要项目存在 “整体、局部操作逻辑统一” 的场景,优先使用组合模式开发,能大幅减少重复代码。
- 异常检测的优先级、程序终止逻辑极易忽略细节
题目明确要求多条错误仅输出第一条、单条语句多错误仅输出高优先级报错,我初期未设置终止逻辑,会一次性打印多条错误提示,和样例输出不匹配;修改为顺序判断,触发任意错误直接 return,不再向下执行校验。
- 输出格式细节繁多,稍有疏漏全部输出错误
普通逻辑门、译码器、数据分配器、子电路元件输出格式完全不同,还要严格遵循固定排序顺序。前期频繁出现排序错乱、译码器多余符号、分配器字符颠倒等问题;后期为每一类电路单元单独封装格式化输出函数,分开处理各类输出规则,出错概率大幅降低。
四、改进建议
- 新建全局常量类,清理代码中零散硬编码参数
当前元件标识符、异常提示文字、各类元件引脚数量、输出排序顺序全部直接写在业务代码中,后期修改参数需要多处改动。新建 CircuitConstant 常量类统一收纳所有固定参数,后续新增元件、修改报错文案仅需修改一处代码。
- 拆分超长运算函数,持续降低代码圈复杂度
译码器、多路选择器当前单个运算方法三四十行,分支嵌套繁琐。可拆分为多个小型独立函数:单独计算控制端二进制编码、单独匹配输出通道,主方法仅负责流程调度,单个函数行数控制在 25 行以内,后期调试定位问题更高效。
- 搭建完整单元测试体系,摆脱纯手动样例测试
目前全部依靠手动输入样例调试,大量边界场景无法覆盖。后续使用 JUnit 编写单元测试,覆盖元件解析、逻辑运算、各类异常报错三大模块;每次修改代码后自动执行回归测试,避免改动代码产生隐性 bug。
- 支持多层嵌套子电路,新增子电路复用功能
当前程序仅支持单层子电路,后续优化为支持多层嵌套;增加子电路复用机制,一段子电路定义完成后,可在主电路中多次引用,减少重复输入内容。
五、阶段综合性总结
1. 本阶段核心学习收获
- 设计模式落地实操:第三次作业重构组合模式,彻底理解统一抽象接口、整体与局部统一操作的核心思路,明确组合模式适用场景,代码复用性、可扩展性显著提升,不再只停留在理论背诵层面。
- 分层工程化开发思维成型:将文本解析、数据存储、电路仿真、异常校验、输出打印完全分层解耦,修改输出格式、新增元件不会污染核心运算代码,局部改动不会影响整体程序运行。
- 掌握自定义领域文本解析、数字电路离散仿真核心思路,可独立处理多级串联、带控制引脚、子电路嵌套的复杂电路拓扑,吃透信号循环迭代收敛仿真原理。
- 建立程序鲁棒性开发意识,不再默认输入全部规范合法,完整的异常捕获、清晰错误提示机制,更加贴合真实工业软件开发场景。
2. 现存短板与后续学习计划
- 时序电路相关知识储备不足:三次作业均为组合电路,未接触时钟、反馈环路、寄存器逻辑。后续主动学习触发器时序原理,完善预留的时钟更新接口,提前为下一轮迭代开发做准备。
- 正则表达式容错能力弱:当前解析器仅识别标准格式输入,多余空格、换行错乱会直接解析失败;给解析器增加文本预处理步骤,自动清洗多余空白字符,提升输入兼容性。
- 自主设计测试用例能力不足:仅依赖题目提供样例,很少主动覆盖空子电路、多层嵌套、多异常混合、全部引脚悬空等极端边界场景;系统学习单元测试思路,全覆盖边界、异常场景。
- 前期架构规划习惯较差:经常写完完整代码后再补画 UML 类图,前期架构缺陷只能大规模重构;后续养成先绘制 UML 类图、梳理类间关系,再动手编码的习惯,减少后期重构工作量。

浙公网安备 33010602011771号