南昌航空大学 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%(良好)

4

4-class

类图核心关系

  • Main:程序入口,仅负责启动主循环,调用的是里面的start()方法,很简单,也可以把初始化放进去;
  • MainLoop:核心流程控制,处理输入、延迟重试、结果展示,为了防止先接后再接前造成的bug;
  • CircuitBuilder:电路构建器,解析输入并创建逻辑门和电源;
  • CircuitManager:电路管理器,存储和管理所有逻辑门与电源;
  • Gate:抽象逻辑门类,定义通用属性和方法,子类实现具体逻辑计算;
  • CreateGate:枚举工厂类,替代 switch 语句创建不同类型的逻辑门,符合开闭原则;
  • Splitter:输入解析工具类,使用正则表达式拆分输入字符串;
  • InputValidator:输入校验工具类,验证引脚号、整数解析等。

设计心得

  • 优点:
    1. 延迟输入处理机制完美解决了 "先连接后定义" 的问题,通过冒泡式重试直到所有连接处理完成;
    2. 枚举工厂模式替代传统 switch 语句,新增逻辑门类型时只需添加枚举项,无需修改原有代码;
    3. 严格遵循单一职责原则,输入解析、电路构建、逻辑计算、结果展示各司其职。
  • 缺点:
    1. Gate 类设计不够灵活,未预留控制引脚和多输出的扩展空间;
    2. 逻辑门查找的 key 设计不合理,使用拼接字符串作为 key,可读性差且容易出错,其实是还好的对于这种不频繁迭代的项目。

2.2 作业 5:复杂逻辑器件仿真系统

核心指标

  • 最大圈复杂度:6(正常)
  • 注释率:16.5%(良好)

5

5-class

类图核心关系

  • SingleOutput/MultiOutput:接口分离单输出和多输出器件,统一输出获取方式;
  • Gate:抽象类新增控制引脚支持,区分普通输入引脚和控制引脚;
  • 新增复杂器件:Decoder(译码器)、DataSelector(数据选择器)、DataDistributor(数据分配器)、TsGate(三态门);
  • CircuitBuilder:扩展支持控制引脚的连接与设置;
  • CircuitManager:优化逻辑门查找 key 的设计,使用类型 - 编号 - 参数的三段式 key。

设计心得

  • 优点:
    1. 接口分离单输出和多输出器件,代码结构清晰,扩展性大幅提升;
    2. 控制引脚与普通输入引脚分离,逻辑更清晰,符合真实电路的设计;
    3. 逻辑门查找 key 优化为三段式,唯一性和可读性大幅提升。
  • 缺点:
    1. 未处理输入信号冲突问题,同一引脚被多个源驱动时会导致结果错误;
    2. 缺少完整的错误处理机制,非法输入时程序会直接崩溃;
    3. 部分复杂器件的计算逻辑可以进一步拆分,降低单个方法的复杂度。

2.3 作业 6:子电路与完整错误处理系统

核心指标

  • 最大圈复杂度:14(偏高)
  • 注释率:0.0%(极差)

6

6-class

类图核心关系

  • ComCircuit:子电路类,实现 MultiOutput 接口,支持独立的内部电路计算和递归调用;
  • MainLoop:新增子电路解析流程和完整的错误处理机制;
  • CircuitBuilder:扩展支持子电路的输入输出引脚连接;
  • InputValidator:新增子电路引用校验、输入输出顺序校验、信号冲突检测;
  • CircuitManager:新增子电路存储和管理功能。

设计心得

  • 优点:
    1. 支持子电路模块化设计,子电路可以像普通逻辑门一样被引用和连接,大幅提升了复杂电路的构建效率;
    2. 完整的错误处理机制,包括输入输出顺序错误、信号冲突、非法子电路引用等,程序鲁棒性大幅提升;
    3. 子电路内部实现独立的计算逻辑,递归处理子电路输出,符合模块化设计原则。
  • 缺点:
    1. MainLoop.processInput()方法过于臃肿,圈复杂度高达 14,包含了子电路解析、主电路解析、错误处理等多重职责;
    2. 注释完全缺失,所有方法和类都没有注释,可维护性极差;
    3. 子电路的计算性能有待优化,每次获取输出都会重新计算所有内部逻辑门。

三、常见问题与修复

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 代码层面:具体优化点

  1. 方法拆分优化:优先拆分 MainLoop.processInput () 方法,将圈复杂度从 14 降低到 7 以下;拆分复杂器件的计算方法,每个方法只实现一个计算步骤;
  2. 注释补充优化:为所有类和公共方法添加完整注释,核心逻辑添加步骤注释,注释率提升到 15% 以上;
  3. 性能优化:子电路计算添加缓存机制,只有输入发生变化时才重新计算,避免重复计算;逻辑门查找使用更高效的数据结构,String串成密码key再用HashMap查找;
  4. 异常体系优化:替换 System.out.println 错误输出为自定义业务异常,通过异常体系统一处理错误,题目要求是只有固定的错误输出,根据面向对象的原则,我们不做过多额外功能

4.3 可维护性优化

  1. 命名规范化:统一变量和方法命名规范,避免使用缩写和无意义的名称;
  2. 单元测试:为核心计算方法(如逻辑门输出计算、子电路计算)编写 Junit 测试用例,覆盖边界场景;
  3. 代码复用:抽离重复的输入解析、校验逻辑为通用工具方法,避免代码重复。

五、总结

5.1 收获与成长

三次逻辑电路仿真作业,让我对面向对象设计有了更深刻的理解:

首先,抽象能力得到了极大提升 —— 把逻辑门、电路、子电路这些抽象概念转化为类和接口,把电平计算、连接处理这些行为转化为方法,真正理解了 "面向对象是对现实世界的建模";

其次,设计原则的应用更加熟练 —— 从作业 4 的单一职责和开闭原则,到作业 5 的接口分离,再到作业 6 的模块化设计,逐步学会了用设计原则指导代码编写;

最后,工程化思维进一步强化 —— 不再只关注功能实现,而是主动考虑鲁棒性、可扩展性、可维护性,学会了通过分层和拆分来管理代码复杂度。

对比之前的 C 语言编程,Java 的面向对象让我学会了 "用积木搭房子",而不是 "用泥巴糊房子"—— 每个类都是一个独立的积木,通过组合可以构建出复杂的系统,而且某个积木坏了可以单独替换,不会影响整个系统。

5.2 不足与待提升

尽管通过了所有测试点,但代码仍有明显短板:

  1. 注释意识严重不足:作业 6 完全没有注释,这是非常严重的问题,必须养成边写代码边写注释的习惯,其实是有点懒把IDEA上面的多.java整合为一个.java文件里;
  2. 方法拆分不够彻底:MainLoop.processInput () 方法过于臃肿,圈复杂度超标,说明单一职责原则的应用还不够熟练,但再拆会很复杂,不做长期维护我就先这样放着了;
  3. 性能考虑不足:子电路每次获取输出都重新计算,没有缓存机制,对于复杂子电路会有性能问题;
  4. 单元测试缺失:所有测试都依赖 PTA 的测试点,没有主动编写单元测试,不利于发现隐藏的逻辑错误。

5.3 总体感悟

逻辑电路仿真系统的三次作业,是我面向对象设计能力的一次全面提升。从作业 4 的基础逻辑门,到作业 5 的复杂器件,再到作业 6 的子电路模块化,我一步步体会到了面向对象设计的魅力 —— 它能把一个复杂的问题拆解成一个个简单的模块,通过模块之间的协作完成整体功能。

写完作业 6 回头看作业 4 的代码,依然有很多可以改进的地方,测试点其实也没有全过(要兼顾SOLID和自己的灵光一现太难了)

posted @ 2026-06-23 15:26  DayingByBy  阅读(3)  评论(0)    收藏  举报