OOP4-6次作业集源码设计与分析总结
写在前面
OOP 作业集第二阶段性学习结束,面向对象程序设计本阶段以数字电路模拟仿真程序为核心,采用迭代增量开发的思想,分三次循序渐进、功能递进的迭代版本拓展电路仿真业务、重构代码架构,完整实践后收获大量Java 实操与面向对象工程化开发经验:
熟练掌握 Java 抽象类、接口、正则输入解析、集合容器、循环迭代仿真、全局信号状态管理等核心编程能力;
落地封装、单一职责、组合模式、多态、高内聚低耦合等核心面向对象设计思路,分层搭建基础逻辑门、带控制引脚组合元件、可复用子电路三层业务类结构;
深刻理解迭代增量开发思想,从仅包含五种基础门电路的仿真程序 1,逐步迭代拓展三态门、译码器、数据选择器等多引脚组合元件形成程序 2,最终新增子电路复用、全链路异常输入检测完善为程序 4;每一轮迭代都会重构原有类结构、修复信号传递逻辑缺陷、扩充业务规则,切实认识到代码可复用性、可扩展性与长期可维护性的工程意义;
学会使用 SourceMonitor 进行代码复杂度量化分析、使用 PlantUML 绘制 UML 类图,基于组合模式设计顶层抽象组件Component、叶子逻辑门Gate、复合子电路Subcircuit,建立先 UML 架构设计、后编码实现、交付前量化评估代码质量的标准化工程开发思维。
Complexity Metrics(复杂度分析)
下文代码质量评估将使用复杂度量化指标,先梳理相关基础概念,本次分析针对三段迭代版本数字电路仿真项目内所有类、方法做复杂度度量。
本次分析核心围绕方法圈复杂度、类整体复杂度两大维度:
方法复杂度分析主要基于圈复杂度的计算。圈复杂度是一种表征程序逻辑复杂程度的软件度量,由程序流程图中独立 “基础执行路径” 的数量推导得出。
v (G):圈复杂度
用来衡量单个方法内 if 分支、循环、多条件判断带来的逻辑复杂度,数值越高,代表需要设计更多测试用例才能完整覆盖全部执行路径。
Avg Complexity (OCavg):类平均圈复杂度
代表整套电路仿真项目整体代码结构的健康程度,数值越低,各类职责划分越清晰、高内聚设计越完善。
Max Complexity:最大圈复杂度
反映项目中逻辑最繁琐、分支最多的单一方法(输入解析、异常校验、仿真迭代循环为高复杂度高发区域)。
WMC:总圈复杂度
为项目内所有方法圈复杂度之和,用于直观评估整套仿真程序的整体调试、维护成本。
Avg Depth:平均嵌套深度
代表 if、for、while 等语句的平均嵌套层级,数值越低,代码线性度越好、可读性越强,不易出现多层嵌套逻辑混乱的问题。
第4次作业:数字电路模拟程序 1(基础逻辑门仿真)
作业要求
本次作业为数字电路仿真基础模块,仅实现五种基础逻辑门电路仿真功能。系统支持读取全局输入电平、解析引脚连线关系,自动传递信号电平;区分与/或/非/异或/同或五种逻辑门,自动计算每个门的输出电平;最后按照规定类型、编号顺序打印有效门电路输出,输入引脚未全部接入信号的元件直接忽略输出。
输入格式包含全局INPUT 电平定义、[]引脚连接语句,全部输入以end作为结束标记;严格遵循引脚命名规则:元件名 - 引脚号,多输入与/或门携带输入数量参数,如A(2)1代表2输入与门1号。
实现方式
采用面向对象分层设计,严格遵循单一职责、封装、多态原则,抽象父类Gate统一规范所有逻辑门行为,五个门作为子类重写计算输出方法;使用 HashMap 容器统一管理全局引脚信号、元件对象。
整体拆分 13 个类:抽象 Gate 基类、AndGate/OrGate/NotGate/XorGate/XnorGate 五个门子类、SignalManager 全局信号管理器、ConnectionManager 连线管理器、GateManager 元件统一调度类、InputParser 输入解析类、OutputGenerator 输出打印类、Pin 引脚实体、Main 程序入口,各类各司其职,通过对象协作完成输入解析、信号传递、逻辑计算、结果打印完整流程。
仿真采用循环迭代更新机制,重复执行「连线信号传递→门电路输出计算」,直至一轮执行无电平更新,终止仿真;输入解析采用字符串分割、字符截取区分元件类型、输入引脚数量、元件编号,规范匹配各类门的引脚编号规则。同时处理引脚重复注册、空行、无效字符等输入细节,保证多组样例正常读取解析。
代码规模
第4次作业代码规模统计如下:

本次项目共 13 个 Java 类文件,总代码 409 行,有效执行语句 263 行;分支语句占比 18.3%,方法调用语句共 116 行;平均每个类包含 3.31 个方法,单个方法平均 4.05 行有效代码;代码注释占比 0%,无业务注释说明。
类图

本次作业类图结构:Main 为主程序入口;抽象 Gate 为所有逻辑门父类,派生 AndGate、OrGate、NotGate、XorGate、XnorGate 五个具体门子类;SignalManager 负责存储所有引脚 0/1 电平;ConnectionManager 记录输出引脚到多个输入引脚的连线映射;GateManager 统一管理全部门元件、提供排序筛选;InputParser 负责解析全部输入文本,创建门、注册引脚、构建连线;OutputGenerator 完成排序后打印有效元件输出;Pin 封装引脚编号与电平状态。
复杂度分析




本次作业的复杂度分析如下:
本次作业共 13 个 Java 类,总代码 409 行,有效执行语句 263 行。项目平均圈复杂度 OCavg=2.19,最大圈复杂度为 11,对应 Main.main () 主方法;全局平均代码嵌套深度 Avg Depth=2.00,最深代码块嵌套层级为 7 层。
可以看出 Main.main()主方法复杂度最高,v(G)=11,原因是内部包含多层循环、分支判断,负责完整仿真迭代循环;其次 InputParser.createGate () 方法圈复杂度 v (G)=10,该方法通过字符正则截取元件类型、参数、编号,多分支判断创建对应逻辑门对象;GateManager.getTypeOrder () 方法 v (G)=6,多分支匹配五类门的输出排序优先级;各类门的 calculate () 计算方法复杂度统一为 3,内部仅简单遍历输入引脚、做二元逻辑判断,逻辑简洁;其余 Getter、构造方法圈复杂度均为 1 或 2。
整体平均嵌套深度 2.00,绝大多数代码嵌套层数集中在 1-3 层,仅主仿真循环、输入解析两处存在深层嵌套;分支语句占比 18.3%,类之间依赖清晰、耦合度低,小型工具方法居多,整体代码结构健康;但本次作业注释占比为 0%,缺少方法、业务流程注释,后期迭代可以补充注释,大幅提升代码可读性与维护性。
Bug 分析
公测
我的程序在公测基础样例全部通过正确性测试,五种逻辑门电平计算、信号跨元件传递、输出排序规则均符合题目样例要求;
最开始仿真循环只执行单次计算,多级串联门电路(如与门输出接非门输入)无法传递二次更新后的电平,下层门输入始终为空,仿真结果全部失效;修复方案改为do-while循环持续迭代,一轮内存在电平更新就重复执行信号传递与门计算,直到无更新停止;
解析多输入与门、或门时,截取括号内输入引脚数量字符串下标写错,读取数字出现空字符串,直接抛出数字转换异常;修正字符串截取左右括号下标边界后正常解析参数;
输出排序时,同类型元件未按编号从小到大排序,输出顺序混乱;新增 Comparator 比较器,先按门类型优先级排序,同类型再对比元件数字编号。
自测
自测过程中,测试边界用例发现多处逻辑漏洞:
判定门输入是否齐全时,仅判断引脚存在,未校验引脚是否有有效电平,空白无输入引脚被判定为完整输入,算出错误输出;新增判断引脚存储电平是否为空,空引脚直接判定输入不完整,忽略该元件输出;
全局 INPUT 输入解析时,带字母引脚读取后,没有存入全局信号管理器,顶层输入电平无法传递到下级门;修正解析逻辑,将全局输入键值对全部存入SignalManager;
输出打印格式缺少 “元件名 - 0: 电平” 规范格式,直接打印数字,与样例输出格式不匹配;拼接固定输出字符串模板,严格匹配题目输出样式。
测试方法
手动构造多组测试样例,覆盖单门电路、多级串联混合门、多输入与,或门,无输入引脚、部分引脚缺失电平、多层信号传递等边界场景,验证五类门逻辑计算、信号迭代更新、输出排序过滤逻辑。
心得
本次作业是整套数字电路仿真迭代项目的起点,通过抽象 Gate 父类、拆分独立管理类,严格遵循单一职责、多态封装的面向对象设计思路,初步掌握分层架构设计方法;同时通过 SourceMonitor 量化复杂度分析、公测互测多组边界用例调试,意识到多层循环、多分支解析会大幅提升方法圈复杂度,输入字符串截取、迭代仿真逻辑是极易出 bug 的薄弱点;也充分体会到迭代开发的优势,本次基础版本搭建了信号、元件、连线三层基础架构,后续迭代新增三态门、译码器、子电路时可以直接复用现有管理器、解析、仿真模块,只新增门子类即可拓展功能,为作业2、作业3的功能扩展与结构优化积累完整工程经验。
第5次作业:数字电路模拟程序 2(扩展组合元件仿真)
作业要求
本次作业为数字电路仿真迭代二,在程序 1 基础上新增带控制引脚的组合逻辑元件,支持九类电路元件仿真运算。系统解析全局输入电平、引脚连线关系,区分基础门、三态门、译码器、数据选择器、数据分配器;新增控制引脚层级规范,严格按控制 - 输入 - 输出排序引脚;迭代循环同步全电路信号电平,依据元件规则计算输出;按固定元件顺序、同元件编号升序打印输出,对输入缺失、高阻无效的元件直接忽略输出,译码器、数据分配器采用专属特殊输出格式。
元件标识符规范:A 与门、O 或门、N 非门、X 异或门、Y 同或门、S 三态门、M 译码器、Z 数据选择器、F 数据分配器;带参数元件名称携带括号标注控制 / 输入引脚数量;输入以 end 作为结束标记,连线约束单一输入引脚仅能绑定一路输出信号。
实现方式
采用面向对象分层设计,严格遵循单一职责、接口多态、抽象封装设计思想,顶层定义CircuitElement统一元件行为接口,抽象父类Gate封装所有元件通用引脚、电平读写、输入校验逻辑,九类元件继承 Gate 并重写计算、输出方法;分层拆分 19 个类,职责完全解耦:
基础实体:Pin封装引脚 ID、电平、有效状态;Wire存储引脚间连线映射
元件实现:AndGate/OrGate/NotGate/XorGate/XnorGate/TriStateBuffer/Decoder/Multiplexer/Demultiplexer 九类元件子类,分别实现专属逻辑运算与输出规则
全局容器:CircuitBoard统一管理全局输入引脚、所有元件、连线关系,全局引脚注册统一检索
输入解析层:InputProcessor正则解析元件名称、拆分 INPUT 全局电平、解析 [] 连线语句,自动匹配创建对应元件,自动补全连线两端引脚对象
仿真调度层:SimulationEngine采用 do-while 迭代仿真,持续同步连线电平、更新元件输出,直至一轮仿真无电平更新终止
输出打印层:OutputGenerator按题目规定元件顺序排序,提取元件数字编号升序排列,区分普通门、译码器、分配器三种输出格式,过滤无效无输出元件
程序入口:Main读取全部输入行,调用解析、仿真、打印流程完成完整运行
整体通过接口多态统一调度全部元件,新增元件仅需新增 Gate 子类,无需修改仿真、解析、输出核心流程,可扩展性强;统一封装引脚激活 / 失效工具方法,集中处理无效高阻状态。
代码规模

第5次作业代码规模统计如下:
本次项目共 18 个 Java 文件、19 个类与接口,总代码 821 行,有效执行语句 548 行;分支语句占比 18.8%,方法调用语句共 234 行;平均每个类包含 4.58 个方法,单个方法平均 4.08 行有效代码;代码注释占比 0%,无业务注释说明。
类图

本次作业类图结构:Main为主程序入口;顶层接口CircuitElement定义所有元件统一行为;抽象类Gate实现接口,派生 AndGate、OrGate、NotGate、XorGate、XnorGate、TriStateBuffer、Decoder、Multiplexer、Demultiplexer 九种具体元件子类;Pin引脚实体、Wire连线实体为底层数据载体;CircuitBoard聚合全部元件、引脚、连线,作为全局电路容器;InputProcessor依赖 CircuitBoard 完成输入解析与元件创建;SimulationEngine依赖 CircuitBoard 驱动迭代仿真;OutputGenerator依赖 CircuitElement 集合完成排序打印。
复杂度分析




本次作业的复杂度分析如下:
本次作业共 19 个 Java 类与接口,总代码 821 行,有效执行语句 548 行。项目平均圈复杂度 OCavg=2.35,最大圈复杂度为 13,对应InputProcessor.createElement()元件创建方法;全局平均代码嵌套深度 Avg Depth=1.95,最深代码块嵌套层级为 6 层。
可以看出InputProcessor.createElement()方法复杂度最高,v (G)=13,内部通过 switch 九分支匹配全部元件类型,存在大量分支判断;其次Decoder.computeOutput()译码器计算方法 v (G)=10,包含循环遍历控制引脚、地址编码计算、批量输出赋值多层逻辑;SimulationEngine.runSimulation()仿真主循环v(G)=9,双层循环遍历元件与连线,持续迭代更新电平;数据分配器 Demultiplexer 计算方法 v (G)=7;各类基础门、三态门计算方法复杂度集中在 2~4,逻辑简洁线性;其余Getter、构造、工具方法圈复杂度均为1或2。
整体平均嵌套深度 1.95,绝大多数代码嵌套层数集中在 1-3 层,仅元件创建、译码器计算、仿真循环三处存在深层嵌套;分支语句占比 18.8%,类之间依赖清晰、低耦合,小型工具方法居多,整体代码结构健康;但本次作业注释占比为 0%,缺少方法、业务流程注释,可读性不足;同时高复杂度分支方法集中在输入解析与译码逻辑,可能是本次程序未拿满分的潜在薄弱点。
Bug 分析
公测
程序基础样例全部通过正确性测试,五类基础门、三态门、基础译码器和选择器输入输出匹配样例要求;但隐藏边界测试点存在未覆盖逻辑,最终得分93分未得满分,也许存在以下未处理完备场景:
元件引脚创建时,部分超长参数译码器、多路分配器引脚编号生成边界校验缺失,极端输入参数下引脚对象创建遗漏,导致引脚电平无法正常传递;
连线解析时,未严格校验 “单一输入引脚不能绑定多路输出” 约束,多输出绑定同一输入引脚时未做冲突拦截,电平覆盖逻辑存在歧义;
全局输入引脚与元件引脚重名场景处理不完善,全局 INPUT 引脚信号优先级逻辑存在缺陷,信号传递冲突;
自测
自测边界用例发现多处逻辑漏洞:
译码器控制引脚 S2、S3求和判断仅做数值相加,未区分 0/1 组合边界,控制信号为 2 时错误判定为正常工作;
数据分配器无效输出拼接时,引脚遍历顺序与题目引脚升序要求不完全匹配,输出字符串 “-” 位置错位;
仿真迭代循环仅在元件初次计算标记 calculated,多轮电平更新后不会重新触发元件重算,多级串联组合电路二次电平更新无法同步刷新输出;
输入空行、仅[]无有效引脚的非法连线行未做完整过滤,空字符串分割数组越界风险未完全规避。
测试方法
手动构造多组测试样例,覆盖单门电路、多级串联组合元件、多控制引脚译码器 / 多路选择器、输入引脚缺失、控制引脚无效、多位数元件编号、全局引脚重名等边界场景,验证九类元件逻辑计算、信号迭代更新、特殊格式输出、元件排序过滤逻辑;利用 SourceMonitor 分析代码复杂度,定位 createElement、Decoder.computeOutput 等高复杂度方法,针对性补充边界校验分支。
心得
本次作业是数字电路仿真迭代开发的第二阶段,在程序 1 基础上拓展多控制引脚组合逻辑元件,通过接口 + 抽象父类的分层架构,深入实践了多态、单一职责、开闭原则的面向对象设计思想;通过 SourceMonitor 量化复杂度分析、公测互测多组边界用例调试,意识到多分支 switch、多层循环计算会大幅提升方法圈复杂度,正则解析、多级迭代仿真、多引脚编号生成是极易遗漏边界条件的薄弱模块;迭代开发架构优势显著,基础引脚、仿真、打印核心模块完全复用,仅新增九类元件子类即可拓展全部新功能,但本次因部分极端边界约束校验不完善未能拿到满分,后续迭代需要强化输入合法性校验、重算刷新机制、命名冲突处理,把底层代码写得更牢靠,方便后续第三版时序元件、第四版子电路和报错检测功能直接迭代升级。
第6次作业(数字电路模拟程序4:子电路+异常检测)源码设计与分析
代码规模

本次作业共 15个Java类,总代码764行,有效执行语句507行。项目平均圈复杂度OCavg=2.23,最大圈复杂度为13。
分支语句占比 17.6%,方法调用语句共 193 条;平均每个类包含 5.13 个方法,平均每个方法仅 4.19 条执行语句;整体平均代码嵌套深度 2.09,最大代码块嵌套深度 7;注释行占比为 0.0%,全程未添加业务、方法注释。
可以看出项目类拆分粒度合理、方法短小精炼,类与类之间耦合度低;但存在单方法逻辑过度耦合、深层代码嵌套等短板,也许是本次作业未拿满分的核心原因。
类图说明

本次程序严格采用题目推荐的组合模式完成架构设计,其中 Main 是主程序入口;顶层抽象类 Component 统一所有电路组件行为,分为两类实现:Gate(叶子节点,包含与、或、非、异或、同或 5 种基础逻辑门,不可包含子组件)、Subcircuit(复合节点,可聚合内部门、连线,支持子电路嵌套引用);
基础实体类:Connection 存储单条连线原始信息与引脚映射、SignalManager 全局统一管理所有引脚电平与输入引脚冲突校验;
工具分层类:InputParser 负责全文本解析(子电路块、主电路输入、连线语句、自动创建元件实例);ExceptionChecker 按题目优先级校验 5 类输入异常;CircuitSimulator 迭代仿真、传递电路信号、递归计算子电路内部元件输出;OutputGenerator 按指定规则排序并打印有效元件输出;
类间关系:Subcircuit 聚合 Component、Connection;所有工具类依赖 SignalManager、Component;Main 依赖全部解析、校验、仿真、输出工具类,统一调度完整业务流程。
复杂度分析




全局最高圈复杂度方法为 InputParser.parseSubcircuit(),v(G)=13,该方法负责完整解析从Cx:至endc的子电路代码块,内部嵌套多层循环、多分支判断(区分INPUT/OUT/连线/结束标记),同时叠加子电路引脚前缀转换、元件自动创建逻辑,大量业务耦合在同一方法内,边界场景极易出错;
次高复杂度方法为 ExceptionChecker.isConnectionInput(),v (G)=10,用于区分连线内引脚属于 “系统输出引脚” 还是 “系统输入引脚”,支撑 5 类异常优先级判断,包含全局输入、子电路内外端口、门输出引脚多层字符串匹配与数字转换逻辑,7 层深度嵌套导致可读性极差;
仿真核心方法 CircuitSimulator.simulate() 复杂度 9,双层循环完成信号传播、元件迭代计算,多级子电路串联时迭代更新逻辑存在时序漏洞;
其余所有门、实体、工具辅助方法均为线性简单逻辑,圈复杂度仅 1~6。
整体平均嵌套深度 2.09,绝大多数代码块嵌套层数控制在 1~3 层,仅解析、异常校验、仿真三处核心业务存在深层嵌套;类拆分遵循单一职责,分层清晰、高内聚低耦合,基础架构设计健康,但高复杂度巨型方法与零注释大幅降低工程可维护性。
Bug 分析
公测
程序基础单门电路、单层子电路样例全部通过正确性测试,基础电平运算、基础异常提示输出符合题目要求;但多层子电路嵌套、多端口子电路场景存在逻辑缺陷:
子电路内外连线端口匹配判断出错,同一条连线同时存在多种异常时,无法按题目指定优先级输出最高等级错误提示;
多级串联子电路仿真迭代终止条件设计缺陷,部分元件电平无法完成多轮刷新,元件输出被遗漏;
子电路多位数编号、多输入输出端口解析存在边界漏洞,引脚前缀拼接错误,子电路端口信号无法正常传递。
自测
自测构造极端边界用例后,暴露多处底层逻辑漏洞:
子电路内部连线与主电路连线共用一套引脚前缀转换逻辑,未区分内部/外部场景,端口信号反向传递;
元件输出排序逻辑对子电路带前缀编号提取不完善,同类子电路元件无法严格按编号升序打印。
测试方法
手动构造全覆盖测试样例,覆盖单层/多层嵌套子电路、多控制端口子电路、5类异常单独/混合出现、输入引脚冲突、多级串联组合电路、多位数元件/子电路编号等边界场景,校验元件运算、异常输出、信号迭代、输出排序全部规则;
使用 SourceMonitor 扫描全项目代码复杂度,定位 parseSubcircuit、isConnectionInput 等高复杂度耦合方法,针对性拆分、优化分支嵌套逻辑。
心得
这次是数字电路仿真第四版迭代,因为时间安排跳过了原定第三版,直接在第一版基础上拓展开发,新增了完整的输入异常检测功能,同时完整落地组合模式,弄懂了普通逻辑门叶子组件和可嵌套子电路复合组件共用同一套抽象接口的设计思路。
我把程序拆成输入解析、异常校验、电路仿真、结果打印几大独立模块,对单一职责、分层解耦这些面向对象设计思路理解得更扎实。处理多层嵌套子电路、分优先级判定报错这类复杂逻辑时我发现,一个方法里堆砌大量分支判断很容易漏掉边界场景、产生 bug;把复杂逻辑拆成多个短小的工具方法、简化多层嵌套,能大幅提升程序稳定性。
分版本迭代开发的优势特别明显,第一版写好的引脚管理、电平传递、各类逻辑门运算底层代码全都能直接复用,本次只新增子电路结构和异常校验模块就实现全部新需求。良好的抽象设计省去了大量重复编码工作,也为后续剩下的时序电路、带反馈电路迭代版本打好了开发基础。
关于设计模式的思考
完成数字电路仿真三次迭代作业时,我还未系统学习各类标准设计模式,且三次作业存在明确的开发约束与技术取舍,各阶段使用、未使用的面向对象实现方式有清晰区分:
第一次基础门电路作业仅依靠抽象类继承、多聚合容器完成开发,全程没有定义统一元件接口、未使用组合模式,元件创建逻辑直接耦合在输入解析代码内,不存在工厂相关封装;
第二次拓展九类组合元件作业新增顶层接口CircuitElement实现多态,抽离出简易元件创建方法,但是依旧没有引入组合模式,所有元件都只能作为独立叶子对象,无法实现模块嵌套复用;
第三次支持子电路嵌套的版本落地题目要求的组合模式,以Component统一所有电路组件行为,但依旧没有封装独立工厂类,也未使用桥接、装饰、单例等其他复杂设计范式,整套程序仅依托继承、接口、类的聚合/依赖关系,搭配单一职责原则搭建分层架构。
整套迭代开发结束后,我将系统学习了完整设计模式知识,对照三段源码复盘设计层面的优缺点。我切实掌握了抽象继承、接口多态、聚合组合、单一职责这些基础 OOP 核心思想,也理解了组合模式处理树形嵌套业务的独特优势;同时清晰意识到本次项目缺失的优化方案:三段代码中元件实例化均存在大量分支判断,完全可以通过标准工厂模式解耦、降低方法圈复杂度,而桥接、装饰等模式本次业务场景无需使用。
经过本次系列开发,我深刻体会到高内聚低耦合、工具类与实体解耦、组合优于多层继承对程序迭代维护的重要意义。后续编写项目时,我会先结合业务场景匹配适配的设计模式,主动用工厂、组合等范式优化巨型分支、深层嵌套等高复杂度代码,持续提升程序拓展能力与可读性。

浙公网安备 33010602011771号