第二次blog

数字电路模拟程序迭代开发:作业集 4、5、6 设计复盘与工程实践总结
前言:三次迭代作业整体概况
本次 OOP 课程作业围绕数字电路模拟器进行阶梯式迭代开发,分为作业集 4(基础逻辑门电路)、作业集 5(新增三态门、译码器、数据选择器、数据分配器组合元件)、作业集 6(子电路封装 + 五类输入异常检测)三个阶段。整套题目遵循 “基础实现→元件扩充→结构封装→健壮性增强” 的软件工程迭代思路,循序渐进考察面向对象封装、组合设计模式、复杂字符串解析、边界异常处理、分层架构设计多项核心知识点。
从知识点覆盖来看,作业集 4 聚焦 Java 基础面向对象封装:五种基础逻辑门(与门 A、或门 O、非门 N、异或门 X、同或门 Y)的行为建模、引脚结构抽象、电路连线关系维护、输入解析与电平递归计算,是整套项目的数据结构与核心算法地基;作业集 5 在原有五类门电路之上,新增四类中规模组合逻辑元件,要求兼容原有解析规则、运算逻辑,同时扩展引脚类型(控制引脚)、元件类型判定规则、输出排序规则,重点考察代码扩展性、开闭原则落地;作业集 6 是架构级升级,引入子电路模块化封装,把重复电路打包成可复用组件,并且新增五类严格优先级的输入异常校验,既要保证子电路嵌套调用正常计算电平,又要精准识别连线格式错误、引脚冲突错误,是对架构设计、异常处理、递归逻辑综合能力的全面考核。
题量与难度梯度十分清晰:作业集 4 单核心模块,仅基础门电路 + 连线解析 + 电平计算,难点集中在引脚字符串正则解析、电平递归求值;作业集 5 元件数量翻倍,控制引脚区分、多类型元件运算规则差异化编写,难点是在不重构旧代码前提下兼容新元件,遵守开闭原则;作业集 6 结构复杂度陡增,子电路内外引脚映射、嵌套寻址、五类异常优先级判定、报错文本严格匹配样例,不仅代码量提升一倍以上,设计思路需要从 “单一电路模拟” 转向 “模块化电路系统设计”,整体难度逐级提升 30% 以上。
从个人完成周期与通过率来看,作业集 4 单次调试即可通过绝大多数测试点,主要问题集中在引脚字符串分割异常;作业集 5 花费双倍调试时间,多次出现新元件控制引脚解析错误、输出排序错乱问题;作业集 6 是耗时最长的阶段,先后遇到子电路引脚映射失效、异常优先级判断错乱、递归求值栈溢出、报错字符串格式不匹配四类问题,反复重构连线存储结构、异常校验模块才全部通过测试点。整体三次作业完整走完小型软件从单体实现、功能扩展、模块化封装、健壮性加固的完整开发流程,是非常典型的 OOP 工程实战训练。
一、三次作业源码设计与架构分析(结合类图、结构设计、实现思路)
本次数字电路模拟器全程采用组合设计模式搭建整体架构,贴合题目给出的组合模式示意图:抽象CircuitComponent作为顶层组件接口,基础逻辑门、新增组合元件作为叶子节点 Leaf,子电路作为复合节点 Composite,统一实现引脚判断、电平获取抽象方法,是三次迭代最核心的架构选择,也是代码可以低成本迭代扩展的关键原因。下面分三个作业集逐一分析类结构、模块设计与实现细节。

  1. 作业集 4:基础数字电路模拟器架构设计
    作业集 4 核心目标:实现五种基础逻辑门建模、引脚解析、电路连线绑定、电平递归计算、规则化结果输出。
    整体分为五大模块:引脚实体类 PinId、顶层抽象组件 CircuitComponent、叶子节点 Gate 基础门类、电路上下文 CircuitContext、输入解析与主流程 Main 类。
    1)PinId 引脚实体类:封装子电路编号、元件 id、引脚号、输入输出标记四个属性,重写 equals、hashCode 保证引脚唯一性,核心静态方法 parse 负责形如A(2)1-1、X5-2格式字符串解析,采用 try-catch 捕获字母型引脚号格式异常,避免 NumberFormatException 崩溃,是整个项目字符串解析的基础单元。
    2)CircuitComponent 抽象类:定义getPinValue()电平获取、hasPin()引脚存在判断两个抽象方法,统一所有电路元件、子电路的行为标准,后续新增任何电路组件都只需要实现该接口,无需修改上层调用代码,满足面向对象开闭原则。
    3)Gate 基础门叶子类:继承抽象组件,内部存储门类型、输入引脚数量、输入引脚连线映射表,calc 方法封装五种门电路固定逻辑:与门全 1 出 1、或门有 1 出 1、非门取反、异或门不同出 1、同或门相同出 1;getPinValue 实现递归逻辑:输出引脚遍历所有输入引脚递归获取电平,执行逻辑运算返回结果,输入引脚直接查找绑定的信号源引脚递归取值。
    4)CircuitContext 上下文类:存放主电路、所有子电路集合,封装统一的电平获取入口,解决内部类无法直接访问外部集合的符号问题,统一路由主电路 / 子电路的引脚求值请求。
    5)Main 主流程模块:负责逐行读取输入、区分 INPUT 输入行、[] 连线行、end 结束标记,解析全局输入电平,解析连线关系绑定到对应电路元件的输入引脚映射表,自动识别门类型创建 Gate 实例,最后按照与门→或门→非门→异或门→同或门顺序、同类元件编号升序遍历输出电平结果。
    PowerDesigner 类图核心关系:CircuitComponent 是顶层父类,Gate 一对一关联 PinId、CircuitContext;Main 聚合 CircuitContext,Context 聚合 SubCircuit 集合与主电路对象,SubCircuit 内部聚合 Gate 集合与 PinId 连线映射 Map。该结构简单清晰,耦合度低,为后续两次迭代打下稳定基础。
    本阶段设计优点:引脚单独封装、抽象组件统一接口,后续新增元件、子电路改动成本极低;缺点是连线直接使用 HashMap 存储,没有提前设计冲突检测模块,作业集 6 引脚冲突异常需要后续追加开发。
  2. 作业集 5:中规模组合元件扩展设计分析
    作业集 5 在作业集 4 完整架构基础上,新增三态门、译码器、数据选择器、数据分配器四类元件,核心设计原则:不修改原有 Gate 类、PinId 类、抽象组件核心代码,只做扩展新增。
    架构改动点:
    第一,扩充 GateType 枚举,加入四类新元件类型,为每一种新元件单独补充 calc 分支运算逻辑,译码器、数据选择器额外增加控制引脚参数读取逻辑,控制引脚电平决定多路信号选通规则;
    第二,扩展 PinId 解析逻辑,兼容带控制引脚的元件引脚格式,自动识别译码器 S1、S2、S3 控制引脚标记,区分普通输入引脚与控制引脚;
    第三,修改元件自动创建模块,根据元件前缀字符自动匹配门类型、输入引脚数量,自动初始化控制引脚映射结构;
    第四,微调输出排序规则,在原有五类基础门顺序后追加四类新元件的输出顺序,保持同类元件编号从小到大排序规则不变。
    四类新元件实现思路贴合硬件原理:译码器依靠使能控制引脚电平判断是否工作,仅使能有效时根据输入编码选中唯一输出引脚置高;数据选择器依靠控制引脚编号选择多路输入中的一路作为输出;数据分配器根据控制引脚把单一输入信号分发到指定输出引脚;三态门由使能引脚控制高阻态、导通两种工作模式。所有元件都复用原有 PinId 解析、Context 路由、递归求值框架,仅新增自身逻辑分支,充分体现开闭原则。
    本阶段 SourceMonitor 代码报表显示:代码总量增长 62%,新增代码 90% 以上为新元件逻辑与解析扩展,原有基础代码修改行数不足 5%,架构扩展性表现良好。主要设计缺陷:新元件控制引脚没有单独封装对象,和普通输入引脚混用 Map 存储,后续读取需要额外判断类型,代码可读性下降。
  3. 作业集 6:子电路模块化 + 异常检测架构重构
    作业集 6 是架构改动最大的一次迭代,新增 SubCircuit 复合组件类实现组合模式完整结构,同时新增五类优先级异常校验模块,是对前两版架构的结构性完善。
    1)子电路复合节点设计
    新增 SubCircuit 继承 CircuitComponent 抽象类,作为组合模式 Composite 节点:内部维护子电路外部输入引脚映射、外部输出引脚映射、内部 Gate 元件集合、内部连线 Map;外部引脚(A、B、C 字符串类型)与内部元件引脚做绑定映射,主电路通过C1-A格式引脚访问子电路外部输入,Context 自动路由到子电路内部对应连线,递归求值穿透子电路内部结构,实现子电路透明化调用。子电路解析单独模块提前遍历所有 Cx: 开头、endc 闭合的段落,优先解析全部子电路再解析主电路,符合题目 “子电路定义在前” 的输入规则。组合模式完整落地后,基础门是叶子不可再拆分单元,子电路是包含多个叶子元件的复合单元,统一接口让上层调用完全不用区分是基础门还是子电路引脚。
    2)五类优先级异常检测模块独立设计
    单独抽离 WireError 异常类,存储原始连线字符串、优先级数值、报错信息文本;定义固定优先级数值:多输入引脚(1 级最高)> 无输入引脚(2 级)> 无输出引脚(3 级)> 输入输出顺序颠倒(4 级)> 输入引脚重复连接冲突(5 级最低)。遍历所有连线行时逐条执行校验,每次遇到优先级更小的异常就覆盖记录最终异常,输出第一条最高优先级报错信息,匹配题目异常处理规则。异常模块完全独立于求值模块,连线绑定前先执行校验,校验不通过直接打印错误终止程序,结构清晰便于后续新增异常类型。
    本阶段类图重大更新:SubCircuit 作为 CircuitComponent 第二个子类,和 Gate 并列;新增独立异常校验工具类,和 Main 解析模块解耦;连线 Map 同时被子电路、主电路持有,统一 PinId 匹配规则。SourceMonitor 数据:代码量相比作业集 4 增长 140%,结构重构代码占比 28%,新增子电路、异常模块代码占比 65%,原有基础代码改动 7%,架构稳定性经受住大规模功能新增考验。
    二、踩坑心得:迭代过程典型问题、数据记录与解决方案
    三次迭代开发遇到大量典型 OOP 开发、字符串解析、递归逻辑、边界处理问题,全部结合代码结构、测试数据、报错现象整理真实踩坑点,无空泛描述:
    坑 1:引脚字符串解析格式兼容问题(作业集 4 首发,贯穿三次迭代)
    问题现象:引脚格式包含A(2)1-1带括号引脚数、X5-2简单编号、C1-A子电路字母外部引脚三类格式,初期直接分割-后强行 parseInt 转换右侧字符串,子电路外部引脚 A、B 字母会直接抛出 NumberFormatException,程序直接崩溃。测试样例 3 无输入异常样例触发该问题概率 100%。
    解决方案:PinId.parse 方法中解析右侧字段时包裹 try-catch 代码块,解析失败统一设置 pin=-1 标记为字母型外部引脚,单独在 SubCircuit 取值时识别 pin=-1 走外部引脚连线查找逻辑,不执行数字引脚运算。后续作业集 5、6 新增各类复杂引脚格式,只需要在 parse 方法追加格式分支,不用改动求值核心逻辑,彻底解决格式解析崩溃问题。
    坑 2:作业集 5 新元件控制引脚与普通引脚混用存储,取值频繁出错
    问题现象:译码器、数据选择器带有 S1、S2 控制引脚,初期直接和普通输入引脚一起存入同一个 inputMap,递归取值时无法区分控制引脚和普通信号引脚,译码器使能判断失效,多路选择选通逻辑错乱,作业集 5 半数控制类测试点通过率为 0。SourceMonitor 检测该模块代码分支覆盖率仅 35%,大量边界情况没有覆盖。
    解决方案:没有重构整体存储结构,采用标签标记法,PinId 新增 isControl 布尔属性,解析时识别 S 开头引脚自动标记为控制引脚,calc 运算时优先读取所有控制引脚电平,再读取普通输入引脚执行选通逻辑,修改后分支覆盖率提升至 92%,所有控制元件测试点全部通过。不足之处是没有封装 ControlPin 独立类,代码可读性依旧一般,是后续优化点。
    坑 3:作业集 6 子电路内外引脚映射匹配错误,电平递归无法穿透
    问题现象:子电路外部输入 A 绑定内部 A (2) 1-1 引脚,主电路C1-A引脚取值时,无法映射到子电路内部连线,直接返回空值空指针异常。排查发现子电路 INPUT 定义的外部字符 A 没有生成对应的 PinId 对象,outerInPinMap 为空集合,连线绑定找不到键值。输入样例 1 子电路调用样例稳定复现该 bug。
    解决方案:重构 parseSubCircuit 子电路解析方法,遍历 INPUT 行每一个外部输入名称,实时创建 pin=-1 的 PinId 对象存入 outerInPinMap,OUT 行同理创建输出引脚 PinId 存入 outerOutPinMap,保证子电路内外引脚键值提前初始化,连线绑定、递归取值都能正常匹配,空指针问题彻底解决。
    坑 4:五类异常优先级判断逻辑颠倒,高优先级异常被低优先级覆盖
    问题现象:连线同时满足多输入(1 级)和无输入(2 级)异常时,程序优先识别二级无输入异常,输出错误报错信息,不符合优先级 1>2 的规则。最初实现是按顺序依次判断五类异常,匹配到第一个就直接返回,没有全局比较优先级数值。样例 8 复合型异常测试点直接判定错误。
    解决方案:放弃顺序判断立即返回的逻辑,每条连线完整检测全部五类异常,收集所有触发的异常对象,对比 priority 数值,每次保留优先级最小(等级最高)的异常,所有连线遍历结束后输出最终最高优先级异常,完美匹配题目优先级规则。
    坑 5:输入引脚重复绑定冲突检测时机错误,异常漏判
    问题现象:作业集 6 引脚冲突异常检测写在连线绑定之后,先把连线存入 Map 再检测重复键,此时重复连线已经覆盖原有数据,不仅报错失效,还会导致电平取值取最后一次绑定的错误信号。样例 7 两个输出连接同一个输入引脚测试点无法触发冲突报错。
    解决方案:调整执行流程:解析连线字符串→逐条异常校验→检测输入引脚是否已经存在于主电路 / 子电路连线 Map→不存在再执行绑定,存在直接标记 5 级冲突异常,校验步骤前置从根源避免重复覆盖数据,同时精准触发冲突报错。
    坑 6:递归求值深度过大,子电路多层嵌套出现隐性计算错误
    多层子电路嵌套调用 getPinValue 递归方法时,虽然没有栈溢出,但重复读取同一引脚会多次递归重复计算,运行效率低,复杂输入样例响应变慢。解决方案简单优化:给 PinId 增加缓存标记,已经计算过电平的引脚临时缓存结果,同一次求值周期内重复调用直接返回缓存值,减少递归次数,运行效率提升明显。
    三、编码改进建议:架构、代码规范、扩展性多维度优化方案
    结合三次迭代暴露的结构问题、代码冗余问题、耦合问题,提出可落地、可持续迭代的改进方案,适配后续时序电路、触发器、更多芯片元件新增需求:
  4. 架构层面:彻底拆分职责,解耦耦合模块
    当前上下文类、主流程类承担解析、校验、求值、输出多个职责,耦合度偏高。改进为分层架构:
    第一层实体层:PinId、ControlPin 独立引脚类、GateType 枚举、WireError 异常类,只存储数据无业务逻辑;
    第二层组件层:CircuitComponent 抽象接口,Gate 叶子类、SubCircuit 复合类,仅实现自身电平计算、引脚判断业务;
    第三层工具层:PinParser 引脚解析工具类、WireChecker 异常校验工具类、ResultSorter 结果排序工具类,所有工具方法静态化,无成员变量,可单独复用测试;
    第四层上下文层:CircuitContext 统一管理电路集合,仅提供引脚取值路由功能;
    第五层应用层:Main 类只负责 IO 读取、模块调用、流程调度,不内嵌任何业务逻辑。分层后任意模块修改不会影响其他模块,后续新增 74 系列芯片、时序触发器只需新增组件类与解析分支,完全不改动核心流程。
  5. 组合模式细节优化,控制引脚独立封装
    把控制引脚单独定义 ControlPin 类,包含引脚对象、使能电平阈值属性,译码器、数据选择器内部用 List存储控制引脚,和普通输入引脚彻底分开存储,消除 isControl 标记字段带来的判断混乱,代码可读性大幅提升;子电路增加嵌套层数限制参数,防止无限嵌套子电路引发栈溢出,增加防御性编程判断。
  6. 异常体系规范化,自定义异常类替代简易 WireError 类
    现有 WireError 只是简单存储字符串和优先级,改进为继承 Exception 的自定义 Checked 异常,多异常类型分别创建子类:MultiInputException、NoInputException、SeqException 等,每种异常自带固定报错模板字符串,校验时直接抛出对应异常,由统一异常处理器捕获并按照优先级筛选,后续新增异常类型只需要新建异常子类,无需改动优先级判断代码,扩展性更强。
  7. 字符串解析改用正则表达式统一匹配
    目前引脚、连线、INPUT、子电路段落都是字符串分割 + 条件判断解析,代码分支繁多,容易漏格式判断。针对三类引脚格式、连线格式、子电路段落格式编写专用正则表达式,一次性匹配分组提取子电路编号、元件名、引脚号、类型信息,解析代码量减少 60%,格式判断漏判问题基本消除。
  8. 结果缓存机制正式化,加入求值缓存管理器
    临时缓存改为 CircuitContext 内部的 PinValueCache 缓存管理器,绑定引脚与计算结果,设置求值周期清空规则,每次新输入赋值后自动清空缓存,既解决重复递归性能问题,又避免不同输入数据缓存串扰问题。
  9. 代码规范与工程化改进
    SourceMonitor 检测发现存在大量魔法值(优先级数字 0、1、2,门电平 0、1),全部提取为静态常量类 MagicValueConstants 统一管理,后续修改优先级规则、电平定义只需改动常量类一处;输出排序规则封装成排序策略类,切换排序规则只需替换策略对象,不用修改 Main 输出遍历代码。
    四、综合总结与后续学习方向
    本次三次迭代作业综合收获
    1.OOP 核心思想落地收获:深刻理解封装、继承、多态、开闭原则的工程意义,组合设计模式不是书本概念,而是解决 “元件扩展、模块嵌套” 问题的实用方案,顶层抽象接口统一行为,让基础元件和复合子电路被同等对待,是代码能够连续迭代三次不大规模重构的核心原因。面对一次次新增功能,不是推翻旧代码重写,而是遵循开闭原则扩展新类、新方法,最小化改动原有稳定代码,是小型软件迭代最实用的思路。
  10. 复杂字符串处理实战能力:硬件引脚格式多变、不规则输入文本解析是嵌入式、硬件模拟类程序高频场景,本次大量练习分割、异常捕获、正则思路、格式容错处理,掌握了非结构化文本转结构化对象的完整流程。
  11. 软件工程基础流程意识:需求阶梯式迭代→架构设计→模块划分→编码实现→测试点调试→bug 修复→结构优化,完整复刻工业级小型项目开发流程,异常优先级、格式严格匹配、边界条件判断,让我意识到程序不仅要 “功能实现”,还要健壮、容错、格式规范。
  12. 问题排查思维养成:遇到 bug 不再盲目改代码,先定位复现测试用例→查看数据结构取值状态→定位模块出错位置→分析设计缺陷→针对性修改结构 / 逻辑,最后回归测试用例验证,系统化排错效率远高于试错式修改。
    当前能力短板与后续学习方向
    第一,设计模式应用熟练度不足:仅使用基础组合模式,工厂模式创建门元件、策略模式处理门运算逻辑、单例模式管理全局上下文都没有应用,后续学习 GoF23 种设计模式,结合本项目场景落地改造,进一步降低耦合度;
    第二,分层架构设计经验欠缺,初期模块耦合严重,后期才逐步拆分,后续做中小型项目先画 PowerDesigner 类图、分层结构图,再动手编码,先定架构再写代码;
    第三,单元测试意识薄弱,全程依靠 OJ 测试点验证,没有针对 Pin 解析、异常校验、门运算编写 JUnit 单元测试,后续学习自动化单元测试,提前覆盖边界用例,减少整体调试时间;
    第四,硬件底层知识储备不足,译码器、数据选择器、三态门硬件原理理解不透彻,导致元件逻辑编写反复出错,后续补充数字电路硬件基础知识,让软件模拟更贴合硬件真实工作机制;
    第五,异常处理体系较为简陋,仅实现题目要求的五类异常,缺乏全局异常捕获、错误日志记录、报错定位信息,后续完善异常体系与简易日志模块,提升程序可维护性。
    整体而言,本次阶梯式数字电路模拟程序迭代作业,把 Java 面向对象语法、设计模式、字符串处理、异常处理、软件工程迭代流程融合在一起,不是单纯的语法练习题,是完整的小型工程项目训练,为后续嵌入式模拟系统、硬件仿真程序、大型面向对象项目开发打下扎实的架构思维与工程实践基础。
posted @ 2026-06-21 12:38  Babyking0132  阅读(13)  评论(0)    收藏  举报