Java面向对象课程作业集4-6总结
一、前言
本篇随笔针对数字电路仿真程序三份OPP迭代作业(作业 4、作业 5、作业 6)做完整复盘。三次任务循序渐进,从基础五类逻辑门仿真,扩充多输出中规模器件,最终实现子电路嵌套、引脚信号冲突校验,分层语法解析整套功能。前期 4、5 版代码设计存在明显缺陷,完全没有按照老师发布OPP4之后要求使用抽象类、接口与多态,直到重构作业6时才补齐继承抽象结构,下文会结合类图、SourceMonitor代码度量报表逐一分析优劣。
1.1 三次作业核心知识点表格
三次知识点难易总览
| 作业编号 | 核心考察知识点 | 新增功能点 |
| 作业四 | 基础类与对象、容器 List/Map、拓扑迭代信号传播(继承接口) | 与 / 或 / 非 / 异或 / 同或五类基础门、全局电平缓存、循环电路迭代运算 |
| 作业五 | HashMap 快速索引、多分支器件逻辑、分层引脚模型(继承接口) | 三态门、译码器、数据选择器、分配器,区分控制 / 输入 / 输出引脚,多输出打印格式化 |
| 作业六 | 抽象类继承、组合模式、递归解析、异常优先级校验 | 抽象 Component 父类、子电路封装嵌套、5 类语法错误分级报错、输入引脚多驱动冲突检测 |
1.2 代码度量总览(SourceMonitor 整体基线)
本次三份源码 Main4.java、Main5.java、Main6.java 统一导出监控报表,整体项目指标如下:
整体:

三份项目指标:

1.3 难度与开发感受
- 作业 4:入门难度,仅 Gate、Main 两个类,只实现了五种基础门电路。整体逻辑简单,所有测试用例一次全部通过。缺点是架构简陋,仅靠依赖关系连接类,没有继承分层。
- 作业 5:难度大幅提升,器件扩充至 9 种,新增分层引脚、多输出打印逻辑。最大问题是所有器件全部塞进单一 Gate 类,依靠海量 if-else 分支区分运算逻辑,computeGate方法圈复杂度直接达到 67,代码耦合严重,违背老师要求的继承、接口设计思路,部分多器件组合测试用例出现引脚索引、打印格式 bug。
- 作业 6:整体业务最复杂,也是我做架构重构的一版。新增抽象父类 Component,Gate、SubCircuit 子类继承抽象类,统一规范所有电路元件的运算、引脚读写行为,用继承多态消除大量分支判断;新增子电路组合结构、分级错误检测。虽解决了前两版的设计缺陷,但代码行数翻倍,注释率大幅下滑,子电路递归计算、异常解析方法嵌套层数偏高。
二、设计与度量分析
2.1 作业 4(Main4.java)分析
代码度量明细

- 类:Main、Gate,合计 2 个;平均每个类仅 2.5 个方法
- 最高复杂度方法:main() 复杂度 33,主方法包揽解析、运算、打印全部流程
- 最大嵌套深度 6 层,平均块深度 2.93
UML 类图结构

仅存在两类:Main、Gate。二者连线为虚线依赖箭头,Main 全局集合存储 Gate 实例,运行时创建、调用门对象。全程无继承、无抽象、无接口,所有门逻辑写在独立静态方法内。
设计优缺点
- 优点:代码简洁,注释充足,基础电路迭代逻辑清晰,无测试用例报错
- 缺陷:完全未使用老师强调的继承与多态;新增器件必须新增静态判断分支,扩展性极差;Main 作为万能主类,职责过于臃肿,不符合单一职责原则
2.2 作业 5(Main5.java)分析
代码度量明细

- 类:Main、Gate,合计 2 个;单文件最大复杂度 67(computeGate)
- 分支语句占比 34.8%,大量 if-else 区分 9 类器件运算逻辑
- 最大嵌套深度 7 层,平均复杂度 13.73,三份代码中复杂度最高
UML 类图结构

依旧只有 Main 与 Gate 两个实体类,依赖虚线连接。Gate 内部新增控制引脚、多输出缓存等属性,但所有器件共用同一个类,依靠type字段区分种类。
设计优缺点
- 优点:引入 HashMap 缓存引脚电平,引脚分层模型贴合硬件结构,基础单器件测试全部通过
- 严重缺陷:依旧没有抽象类、继承、接口设计,是前三版里架构问题最突出的一份;computeGate几十行分支判断,维护、修改成本极高;多输出器件打印逻辑耦合在同一方法,极易出现格式化 bug
2.3 作业 6(Main6.java,重构版)分析
代码度量明细

- 类:Main、抽象 Component、Gate、SubCircuit,合计 4 个类,新增抽象与继承结构
- 最高复杂度 26(子电路compute()),相比作业 5 的 67 大幅下降
- 最大嵌套深度 8 层,平均复杂度仅 6.39,分支冗余明显减少
完整 UML 类图关系说明

- 泛化(继承):实线空心三角箭头,Gate、SubCircuit 共同继承抽象父类 Component,实现全部抽象方法compute()、getOutput()、打印、引脚校验方法,补齐老师要求的继承设计;
- 聚合关系:SubCircuit 使用空心菱形实线连接 Component,内部children集合存放门与嵌套子电路,元件生命周期与子电路解绑;
- 依赖关系:Main 虚线箭头指向 Component,主程序仅调度顶层抽象组件,不再直接耦合 Gate、SubCircuit;
重构改进点
- 弥补作业 4、5 最大设计漏洞:引入抽象 Component 基类,利用继承、抽象方法实现多态,删除作业 5 海量器件分支判断;新增统一行为规范,使得后续新增器件仅需新建子类,无需修改原有运算代码;
- 引入组合模式实现子电路嵌套,独立封装子电路输入输出端口、内部连线,降低代码耦合性;
- 增加五级优先级语法异常检测,能识别多引脚信号冲突、无输入 / 无输出连线等错误;
现存不足
- 注释率仅 4.8%,复杂递归、异常解析逻辑缺少文字说明;
- 子电路compute()、解析parseConn()嵌套层次偏多,可继续拆分子方法降低复杂度;
- 全局缓存、错误列表全部放在 Main 静态变量中,主类职责依旧偏重。
部分分析参考AI分析结果
三、开发踩坑复盘
坑 1:前期无继承架构,分支爆炸(作业 4、5 共性问题)
问题:4、5 版全器件共用 Gate 实体类,靠type判断运算逻辑,computeGate分支越写越长,修改一种器件逻辑就要通读全部 if-else,易改错其他门电路,译码器打印格式 bug 就是分支判断疏漏导致。
解决:作业 6重构抽象 Component,各类器件各自重写 compute 运算方法,各司其职,彻底消除超长分支。
反思:在设计群老师明确说明后续作业需要使用继承、接口,但我前两次作业图省事直接放弃分层抽象,不仅代码质量差,还出现业务 bug,架构设计思维不到位。
坑 2:子电路端口命名域冲突(作业 6 核心 bug)
问题:子电路内部短端口名(A、Y)和全局带前缀引脚(C1-A)重名,初次运行读取电平全部为空,子电路无法参与运算。
解决:子电路内部维护本地输入输出映射表,内部连线优先读取局部端口缓存,跨子电路访问再拼接全局前缀。
坑 3:多输入引脚信号冲突检测缺失
问题:两条连线同时驱动同一个门输入引脚时,程序未做校验,电平覆盖混乱,对应题目异常 5。
解决:新增全局、子电路两层驱动记录表,解析连线时判断目标引脚是否已有驱动源,重复驱动直接抛出指定错误信息。
坑 4:迭代电平缓存递归死循环
问题:跨子电路互相引用引脚时,递归求值无限循环,栈溢出。
解决:新增临时计算标记集合,求值过程中标记正在计算的引脚,避免循环递归。
四、长期优化改进方案
4.1 架构优化(解决前两版无继承、高耦合问题)
- 接口分层:后续可新增ICircuitCalc运算接口,所有组件实现接口,进一步分离行为与实体;
- 拆分 Main 主类:将文本解析、电平缓存,错误管理拆分为独立工具类,消除万能 Main;
- 工厂模式创建器件:新增 Gate 工厂,根据类型自动生成对应子类实例,完全删除类型判断代码。
4.2 代码细节优化
- 拆解高复杂度方法:把子电路compute()、parseConn()拆分为端口初始化、内部连线运算、输出缓存三步独立子方法,降低嵌套深度;
- 统一常量管理:把正则表达式、错误提示、引脚前缀全部提取静态常量,消除代码内 “神秘字符串”;
- 完善注释规范:给抽象类、递归、异常校验核心方法增加功能、参数说明,提升注释率。
4.3 健壮性优化
- 自定义电路异常类,替换当前直接打印报错、终止程序的写法;
- 增加输入文本格式预校验,提前拦截非法门名称、子电路语法,减少运行时空指针。
部分优化方案参考AI提议
五、整体总结与自我反思
5.1 本次作业收获
- 从无分层与单一实体类到抽象父类 + 子类继承的完全面向对象架构,真正理解了老师在设计群强调的继承、抽象、多态的实际用处,不再只停留在语法背诵与普通理解;
- 基本掌握组合模式实现层次化组件方法,基本学会用聚合、泛化、依赖三种 UML 关系划分与理解类之间的协作逻辑;
- 熟练使用 SourceMonitor 量化评估代码质量,能通过圈复杂度、嵌套深度、分支占比定位劣质代码,找出代码设计漏洞;
- 理解了层次化命名空间、递归求值,多驱动校验等工程化思路,建模更贴合真数字硬件逻辑。
5.2 自身明显短板
- 前期作业规划不足,作业 4、5 完全忽略老师要求的继承与接口设计,只追求功能跑通,架构存在根本性缺陷,直到作业 6 重构才修正,浪费大量调试时间与测试精力;
- 编码前期缺少代码质量意识,作业 5 放任computeGate分支疯狂膨胀即一股脑全赛里面,没有及时拆分、抽象;
- 注释书写习惯较差,迭代到作业 6 时注释几乎空白,复杂的逻辑的可读性大幅下降;
- 不会提前预判分层场景与子电路嵌套、跨层引脚访问这类复杂的场景,前期没有预留扩展结构与计划。
5.3 课程作业学习感悟
三次迭代作业清晰地体现出了先设计、后编码的重要性。作业 4、5 时只追求快速实现功能,忽略了面向对象分层的规范,代码耦合、复杂度双双登顶,还出现了业务 逻辑bug;而作业 6 先按照老师要求搭建抽象继承架构,再填充业务逻辑,不仅代码结构规范,还一次性解决前两版大量遗留问题。
这次也记住了老师的提醒:后续作业必须使用继承与接口,不能一味地只用单一类堆砌功能导致代码冗长。明白了面向对象核心不是写类,而是抽象分层、复用拓展的道理,我今后写程序会先绘制 UML 类图梳理继承、组合关系,再动手编码,避免再出现架构层面的低级错误。
5.4 对课程作业的小建议
- 布置作业前可以简单地演示抽象类、继承在同类项目中的使用案例先,方便我们提前搭建规范架构;
- 课堂增加简单UML类图绘图练习,强化类间泛化、聚合、依赖关系的区分;
- 每次作业增加代码度量检查要求,提前提醒高复杂度、无注释、无继承等设计问题,不用等到复盘才发现缺陷。
