面向对象编程实验一

一、前言
本阶段三次题目集主要围绕电梯调度系统的设计与实现展开,涵盖了面向对象编程的核心概念和设计原则。这三次题目如下:

  • 第一次作业:设计一个电梯类,实现单部电梯基础调度,处理内呼外呼请求,遵循同方向优先规则。
  • 第二次作业:对之前电梯调度程序进行迭代性设计,解决电梯类职责过多的问题,要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类等。且加入了输入错误的修正。
  • 第三次作业:对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类。

从上述题目可见,三次作业的核心变化在于“从代码实现到设计架构”的转变。第一批次仅要求完成功能,第二批次通过强制拆分类职责引入设计原则,第三批次则通过实体完善(新增乘客类)让面向对象模型更贴近真实场景。这种演进难度不断上升,也符合软件开发从“编码”到“架构”的实际需求。

二、设计与分析
第一次作业类图设计:

屏幕截图 2025-11-22 182107

以下是使用SouceMonitor对第一次代码的分析:

屏幕截图 2025-11-22 182528

屏幕截图 2025-11-22 182540

屏幕截图 2025-11-22 182548

优点:

  • 核心实体封装到位:Elevator 类完整封装了电梯的核心状态(maxLayer/minLayer/nowLayer/runDirection)和行为(run/changeDiretion/outputStatus),所有状态修改仅通过类内方法完成,避免外部直接操作属性,符合面向对象 “封装” 核心思想;
  • 类间依赖关系清晰:类图中明确体现 Main 依赖 Elevator 的单向关系,Main 负责控制流程,Elevator 负责电梯实体行为,无循环依赖,基础架构无致命缺陷。
  • 正则匹配简化输入解析
    通过 Pattern 预编译正则表达式,精准匹配内 / 外部请求格式(<楼层>/<楼层,方向>),相比字符串切割等方式,正则匹配的鲁棒性更强,能有效区分不同类型的请求,降低输入解析的出错概率。

不足:

  • Main 类职责过度集中:类图中 Main 同时承担 “输入解析(inputInformation)、调度控制(controlElevator)” 两类核心职责,未拆分出 “输入解析类、调度控制类”,后续修改任一模块都会影响整体;
  • Elevator 类职责混杂:Elevator 既管理电梯状态(楼层 / 方向),又维护请求队列(insideQueue/withoutQueue),还负责输出打印(outputStatus/outputDoor),这个类包揽 “实体状态、数据存储、视图输出”,修改输出格式需改动电梯核心类,耦合度高;
    *流程嵌套层级过深:controlElevator 流程图中嵌套层级达 5 层(while 循环 + 多层 if-else),圈复杂度高达 19,逻辑分支交织,调试时难以定位问题。

第二次作业类图设计:

222

以下是使用SouceMonitor对第二次代码的分析:

屏幕截图 2025-11-22 184449

屏幕截图 2025-11-22 184504

屏幕截图 2025-11-22 184513

屏幕截图 2025-11-22 184625
优点:

  • 类职责拆分更合理:新增了 ExternalRequest 类封装外部请求、RequestQueue 类管理内外部请求队列、Controller 类负责调度逻辑,Elevator 类专注于电梯状态管理。这种拆分遵循了单一职责原则,每个类只负责一个核心功能,降低了代码耦合度,且类的职责颗粒度更均匀,避免了单个类逻辑过于臃肿的问题。
  • 复杂度控制有提升:最大圈复杂度从 19 降至 11(Controller.move() 方法),平均复杂度从 3.13 降至 2.40,最大块深度保持在 5 但整体平均块深度从 2.41 降至 2.06。这说明方法逻辑的嵌套和分支得到了一定优化,代码的可理解性有所提升。除 Controller.move() 外,其他方法的复杂度普遍较低(如 Elevator 类的方法复杂度均为 1),说明基础功能的封装较为简洁。

不足:

  • 核心方法仍存在复杂度风险:Controller.move() 方法的圈复杂度为 11,包含 33 条可执行语句,且逻辑仍较为耦合。虽然相比之前的 19 有进步,但仍超过了行业建议的阈值(≤10)。Controller.determineDirection() 和 Controller.getNextFloor() 方法的复杂度也较高(分别为 11 和 7),逻辑嵌套较深,需要进一步拆分。
  • 注释与命名仍需优化:注释行占比仅 1.6%,核心方法(如 determineDirection、getNextFloor)缺乏详细的逻辑说明。

第三次作业类图设计:

333

以下是使用SouceMonitor对第三次代码的分析:

屏幕截图 2025-11-22 185640

屏幕截图 2025-11-22 185653

屏幕截图 2025-11-22 185712

屏幕截图 2025-11-22 185727

优点:

  • 类职责与实体封装更完善:新增 Passenger 类封装乘客的 “起点楼层” 和 “目标楼层”,将外部请求从单纯的 “楼层 + 方向” 升级为 “乘客全流程需求”,使模型更贴近真实场景,实体关系更清晰。
  • 复杂度与结构进一步优化:最大圈复杂度从 11 至 12(Controller.processRequests() 方法),但平均复杂度从 2.40 降至 2.27,方法粒度更均匀(平均每方法 3.88 条语句)。Controller.move() 方法的复杂度从 11 降至 11 但语句数减少(从 33 条到 27 条),逻辑耦合有所降低。

不足:

  • 核心方法复杂度仍需优化:Controller.processRequests() 圈复杂度为 12,Controller.determineDirection() 为 11,这些方法的逻辑仍较密集,,需进一步拆分为更小的子方法。
  • 注释与命名的不足延续:注释行占比仅 1.5%,核心业务方法(如 determineDirection、getNextFloor)缺乏详细的逻辑说明。

三、采坑心得

  1. 运行超时
    在写第一次作业的时候,提交的代码总是运行超时。后面发现在每一层都输出当前状态和判断是否开门太耗时;于是改成了直接到达下一次开门的楼层,在开门的楼层中一次性输出中间经过的楼层。只有程序耗时减少,可以通过测试了。
  2. 逻辑判断
    在开始做作业时,没有想清楚所有情况。以为只需要判断电梯现在的方向与到内部的方向、电梯现在的方向与外部请求的方向是否相同,再进行移动;没有考虑到电梯现在的方向与外部请求的方向相同,但电梯现在的方向与到外部请求的方向不相同的情况(现在楼层:7,现在方向:UP,外部楼层:3,外部方向:UP),导致运行时出错。
  3. 类分工不明确
    由于第一次写作业时只注重能否实现功能,没有进行类的拆分。使 Main 同时承担输入解析和调度控制两类核心职责,Elevator 既管理电梯状态,又维护请求队列,还负责输出打印;导致第二次作业要求拆分迭代,整个代码都要重写。好在第二次认真拆分,第三次的代码就不需要改多少。

四、改进建议

  1. 最后的代码核心方法复杂度仍需优化,Controller.processRequests() 圈复杂度为 12,Controller.determineDirection() 为 11,这些方法的逻辑仍大于10,需进一步拆分为更小的子方法。
  2. 最后的注释行占比仅 1.5%,核心业务方法仍然缺乏详细的逻辑说明。

五、总结
通过这三次作业,我从 “实现功能就好” 彻底转向 “设计思想导向” 的编码思维。最初仅用Main和Elevator两个类堆砌逻辑,到拆分出RequestQueue、Controller、Passenger等类,理解了单一职责原则的核心 —— 并非简单拆分代码,而是让每个类对应真实场景中的一个实体 / 行为,如Passenger类封装乘客的起点、终点和乘梯方向,Controller专注调度逻辑,Elevator仅管理自身状态,这种设计让代码的可维护性和扩展性提升。

希望下次作业不要只有一个测试点,有什么问题全靠猜。(也希望案例不要出错QAQ)

posted @ 2025-11-22 22:27  木木行星  阅读(0)  评论(0)    收藏  举报