南昌航空大学 2025 级 Java 面向对象的程序设计作业集 4-6 总结
一、前言
这门课的 OOP 作业围绕逻辑电路仿真系统展开三次迭代(作业 4~6)。三次作业从基础逻辑门建模到复杂子电路支持,要求在上一次的题目上做了改变,这次作业四为主体,作业五和六为迭代。以下是三次作业的核心跨度总结:
1.1 知识点覆盖
| 作业集 | 核心知识点 |
|---|---|
| 作业 4 | 基础逻辑门电路(与 / 或 / 非 / 异或 / 同或) |
| 作业 5 | 加上了复杂逻辑器件(译码器 / 数据选择器 / 分配器 / 三态门)、控制引脚建模、单输出 / 多输出接口分离、抽象类与接口协作(算是自己加的) |
| 作业 6 | 子电路(也算是嵌套)支持、输入信号冲突检测、完整错误处理机制、递归电路计算、分层架构设计 |
1.2 量化指标对比
| 指标 | 作业 4 | 作业 5 | 作业 6 |
|---|---|---|---|
| 源码行数 | 696 | 995 | 1299 |
| 类数量 | 16 | 22 | 20 |
| 平均方法数 / 类 | 3.06 | 5.27 | 13.60 |
| 平均语句数 / 方法 | 6.33 | 4.00 | 0.54 |
| 最大圈复杂度 | 6 | 6 | 14 |
| 注释率 | 16.7% | 16.5% | 0.0% |
1.3 难度感受
- 作业四:聚焦基础逻辑门的抽象与输入顺序问题,核心难点是解决 "先连接后定义" 导致的计算错误,延迟输入处理机制的设计花了大量时间;
- 作业五:引入控制引脚和多输出器件,需要重新设计 Gate 类的结构,不然不同的接口数量会导致原代码逻辑的bug,接口分离单输出和多输出是关键,译码器的控制引脚逻辑容易出错;
- 作业六:重新以作业四开始迭代,之前作业五的内容全部移除,子电路支持和错误处理是核心,需要实现子电路的独立计算与递归调用(但目前还只支持单次调用,不能二次嵌套),输入冲突检测和完整的错误体系大幅增加了代码复杂度。
二、设计与分析
2.1 作业 4:基础逻辑门仿真系统
核心指标
- 最大圈复杂度:6(正常)
- 注释率:16.7%(良好)


类图核心关系
Main:程序入口,仅负责启动主循环,调用的是里面的start()方法,很简单,也可以把初始化放进去;MainLoop:核心流程控制,处理输入、延迟重试、结果展示,为了防止先接后再接前造成的bug;CircuitBuilder:电路构建器,解析输入并创建逻辑门和电源;CircuitManager:电路管理器,存储和管理所有逻辑门与电源;Gate:抽象逻辑门类,定义通用属性和方法,子类实现具体逻辑计算;CreateGate:枚举工厂类,替代 switch 语句创建不同类型的逻辑门,符合开闭原则;Splitter:输入解析工具类,使用正则表达式拆分输入字符串;InputValidator:输入校验工具类,验证引脚号、整数解析等。
设计心得
- 优点:
- 延迟输入处理机制完美解决了 "先连接后定义" 的问题,通过冒泡式重试直到所有连接处理完成;
- 枚举工厂模式替代传统 switch 语句,新增逻辑门类型时只需添加枚举项,无需修改原有代码;
- 严格遵循单一职责原则,输入解析、电路构建、逻辑计算、结果展示各司其职。
- 缺点:
- Gate 类设计不够灵活,未预留控制引脚和多输出的扩展空间;
- 逻辑门查找的 key 设计不合理,使用拼接字符串作为 key,可读性差且容易出错,其实是还好的对于这种不频繁迭代的项目。
2.2 作业 5:复杂逻辑器件仿真系统
核心指标
- 最大圈复杂度:6(正常)
- 注释率:16.5%(良好)


类图核心关系
SingleOutput/MultiOutput:接口分离单输出和多输出器件,统一输出获取方式;Gate:抽象类新增控制引脚支持,区分普通输入引脚和控制引脚;- 新增复杂器件:
Decoder(译码器)、DataSelector(数据选择器)、DataDistributor(数据分配器)、TsGate(三态门); CircuitBuilder:扩展支持控制引脚的连接与设置;CircuitManager:优化逻辑门查找 key 的设计,使用类型 - 编号 - 参数的三段式 key。
设计心得
- 优点:
- 接口分离单输出和多输出器件,代码结构清晰,扩展性大幅提升;
- 控制引脚与普通输入引脚分离,逻辑更清晰,符合真实电路的设计;
- 逻辑门查找 key 优化为三段式,唯一性和可读性大幅提升。
- 缺点:
- 未处理输入信号冲突问题,同一引脚被多个源驱动时会导致结果错误;
- 缺少完整的错误处理机制,非法输入时程序会直接崩溃;
- 部分复杂器件的计算逻辑可以进一步拆分,降低单个方法的复杂度。
2.3 作业 6:子电路与完整错误处理系统
核心指标
- 最大圈复杂度:14(偏高)
- 注释率:0.0%(极差)


类图核心关系
ComCircuit:子电路类,实现 MultiOutput 接口,支持独立的内部电路计算和递归调用;MainLoop:新增子电路解析流程和完整的错误处理机制;CircuitBuilder:扩展支持子电路的输入输出引脚连接;InputValidator:新增子电路引用校验、输入输出顺序校验、信号冲突检测;CircuitManager:新增子电路存储和管理功能。
设计心得
- 优点:
- 支持子电路模块化设计,子电路可以像普通逻辑门一样被引用和连接,大幅提升了复杂电路的构建效率;
- 完整的错误处理机制,包括输入输出顺序错误、信号冲突、非法子电路引用等,程序鲁棒性大幅提升;
- 子电路内部实现独立的计算逻辑,递归处理子电路输出,符合模块化设计原则。
- 缺点:
MainLoop.processInput()方法过于臃肿,圈复杂度高达 14,包含了子电路解析、主电路解析、错误处理等多重职责;- 注释完全缺失,所有方法和类都没有注释,可维护性极差;
- 子电路的计算性能有待优化,每次获取输出都会重新计算所有内部逻辑门。
三、常见问题与修复
1. 输入顺序问题
问题:作业 4 中如果输入先连接后定义的逻辑门,会导致源电平获取失败,计算结果错误。
修复:设计延迟输入处理机制,将无法立即处理的连接加入延迟队列,循环重试直到所有连接处理完成或无法继续处理。
心得:逻辑电路仿真中输入顺序是不可控的,必须设计能够处理任意输入顺序的机制,这是电路仿真系统的核心难点之一。
2. 多输出器件支持
问题:作业 4 的 Gate 类只支持单输出,无法实现译码器、数据分配器等多输出器件,未给后续迭代留增口。
修复:通过 SingleOutput 和 MultiOutput 接口分离单输出和多输出器件,MultiOutput 接口定义数组形式的输出方法,但作业六又重回作业四所以没有太大迭代用处。
心得:接口是实现多态的核心,通过接口分离不同行为的对象,可以让代码结构更清晰,扩展性更强。
3. 输入信号冲突
问题:作业 5 中同一输入引脚被多个源驱动时,后写入的值会覆盖先写入的值,导致结果错误且无法检测。
修复:作业 6 中新增输入信号冲突检测,在处理连接时记录每个目标引脚的源,如果发现不同的源驱动同一引脚,立即抛出错误。
心得:真实电路中不允许同一引脚被多个源驱动,仿真系统必须严格模拟这一规则,否则会导致错误的计算结果。
4. 子电路递归计算
问题:子电路内部包含其他逻辑门甚至子电路,需要实现独立的计算逻辑。
修复:ComCircuit 类内部维护独立的逻辑门集合和输入输出映射,每次获取输出时重新计算所有内部逻辑门,实现递归调用。
心得:子电路的本质是一个封装好的黑盒,对外只暴露输入输出引脚,内部实现完全透明,这是模块化设计的核心思想。
5. 注释缺失问题
问题:作业 6 注释率为 0,所有核心方法和类都没有注释,后期维护时需要逐行阅读代码才能理解逻辑。
修复:补充类注释(说明核心职责和设计思路)、方法注释(参数、返回值、功能)和核心逻辑步骤注释。
心得:注释是代码的生命线,尤其是复杂的逻辑电路仿真系统,缺少注释的代码即使是自己写的,几个月后也会完全看不懂。
6. 方法臃肿问题
问题:MainLoop.processInput () 方法包含了子电路解析、主电路解析、错误处理、冲突检测等多重职责,圈复杂度高达 14。
修复:将 processInput () 方法拆分为 parseSubCircuits ()、parseMainCircuit ()、checkConnectionConflict () 等多个独立方法,每个方法只做一件事。
心得:单一职责原则不仅适用于类,也适用于方法,一个方法的职责越单一,可读性和可维护性就越好,圈复杂度也越低。
四、改进建议
4.1 架构层面:进一步分层解耦
当前 MainLoop 类承担了过多职责,可以拆分为以下独立类,实现更清晰的分层架构:
| 分层 | 核心职责 | 对应类示例 |
|---|---|---|
| 输入层 | 原始输入读取与解析 | InputReader、LineParser |
| 校验层 | 语法与语义校验 | SyntaxValidator、SemanticValidator、ConflictDetector |
| 构建层 | 电路与子电路构建 | CircuitBuilder、SubCircuitBuilder |
| 计算层 | 电路逻辑计算 | CircuitEvaluator、SubCircuitEvaluator |
| 错误层 | 错误收集与处理 | ErrorCollector、ErrorHandler |
| 展示层 | 结果格式化输出 | ResultDisplayer |
拆完后类数量会来到18个左右,但这次之后不会再进一步迭代所以忽略不计
4.2 代码层面:具体优化点
- 方法拆分优化:优先拆分 MainLoop.processInput () 方法,将圈复杂度从 14 降低到 7 以下;拆分复杂器件的计算方法,每个方法只实现一个计算步骤;
- 注释补充优化:为所有类和公共方法添加完整注释,核心逻辑添加步骤注释,注释率提升到 15% 以上;
- 性能优化:子电路计算添加缓存机制,只有输入发生变化时才重新计算,避免重复计算;逻辑门查找使用更高效的数据结构,String串成密码key再用HashMap查找;
- 异常体系优化:替换 System.out.println 错误输出为自定义业务异常,通过异常体系统一处理错误,题目要求是只有固定的错误输出,根据面向对象的原则,我们不做过多额外功能
4.3 可维护性优化
- 命名规范化:统一变量和方法命名规范,避免使用缩写和无意义的名称;
- 单元测试:为核心计算方法(如逻辑门输出计算、子电路计算)编写 Junit 测试用例,覆盖边界场景;
- 代码复用:抽离重复的输入解析、校验逻辑为通用工具方法,避免代码重复。
五、总结
5.1 收获与成长
三次逻辑电路仿真作业,让我对面向对象设计有了更深刻的理解:
首先,抽象能力得到了极大提升 —— 把逻辑门、电路、子电路这些抽象概念转化为类和接口,把电平计算、连接处理这些行为转化为方法,真正理解了 "面向对象是对现实世界的建模";
其次,设计原则的应用更加熟练 —— 从作业 4 的单一职责和开闭原则,到作业 5 的接口分离,再到作业 6 的模块化设计,逐步学会了用设计原则指导代码编写;
最后,工程化思维进一步强化 —— 不再只关注功能实现,而是主动考虑鲁棒性、可扩展性、可维护性,学会了通过分层和拆分来管理代码复杂度。
对比之前的 C 语言编程,Java 的面向对象让我学会了 "用积木搭房子",而不是 "用泥巴糊房子"—— 每个类都是一个独立的积木,通过组合可以构建出复杂的系统,而且某个积木坏了可以单独替换,不会影响整个系统。
5.2 不足与待提升
尽管通过了所有测试点,但代码仍有明显短板:
- 注释意识严重不足:作业 6 完全没有注释,这是非常严重的问题,必须养成边写代码边写注释的习惯,其实是有点懒把IDEA上面的多.java整合为一个.java文件里;
- 方法拆分不够彻底:MainLoop.processInput () 方法过于臃肿,圈复杂度超标,说明单一职责原则的应用还不够熟练,但再拆会很复杂,不做长期维护我就先这样放着了;
- 性能考虑不足:子电路每次获取输出都重新计算,没有缓存机制,对于复杂子电路会有性能问题;
- 单元测试缺失:所有测试都依赖 PTA 的测试点,没有主动编写单元测试,不利于发现隐藏的逻辑错误。
5.3 总体感悟
逻辑电路仿真系统的三次作业,是我面向对象设计能力的一次全面提升。从作业 4 的基础逻辑门,到作业 5 的复杂器件,再到作业 6 的子电路模块化,我一步步体会到了面向对象设计的魅力 —— 它能把一个复杂的问题拆解成一个个简单的模块,通过模块之间的协作完成整体功能。
写完作业 6 回头看作业 4 的代码,依然有很多可以改进的地方,测试点其实也没有全过(要兼顾SOLID和自己的灵光一现太难了)

浙公网安备 33010602011771号