面向对象设计课程第一单元-电梯题目集总结性Blog

一、前言

题目集结构与知识点分布

题目集 题量 核心知识点
第一次 5题 身份证校验算法、一元二次方程类设计、正则表达式(验证码/QQ号)、电梯调度基础
第二次 3题 点与线类封装、汽车风挡玻璃雨刷问题(类设计)、单部电梯调度程序(类设计)
第三次 3题 销售步枪问题、蒙特卡罗方法(圆周率)、电梯调度迭代设计(SRP原则、乘客类与队列分离)

难度梯度分析

第一次题目集(入门→中等)

  • 基础能力训练
    • 以正则表达式(7-3、7-4)和简单类设计(7-2)为主
    • 难度集中在算法实现(7-1身份证校验)和电梯调度逻辑(7-5)
  • 挑战点
    • 电梯调度需处理多状态切换(运行方向、请求队列)
    • 初次接触时对条件分支复杂度预估不足

第二次题目集(中等)

  • 设计模式深化
    • 汽车雨刷问题(7-2)要求设计状态机
    • 销售步枪问题(7-1)强化单一职责原则
  • 数学建模实践
    • 点与线类(7-1)需精确处理坐标计算与格式化输出
    • 代码容错性要求高(输入范围校验)

第三次题目集(较难)

  • 系统级设计
    • 电梯调度程序迭代(7-3)需解耦乘客类、队列类与控制类
    • 严格遵循SRP原则
  • 算法与性能
    • 蒙特卡罗仿真(7-2)涉及大规模随机数生成
    • 计算效率优化(如减少浮点运算次数)

综上总结三次题目集的知识点、题量、难度等情况

  • 这三次题目集每个题目集基本都是给一周左右的时间完成,题目量为3-5题,前几题都是比较简单的设计类和对象题目,正则表达式基础训练题目,每个题目集的最后一题就是迭代编程作业:单部电梯调度程序题目,这道题目难度是比较大的,也是整个题目集的重中之重。

二、本轮迭代编程作业存在的问题

第一次NCHU_单部电梯调度程序

点击查看题目详细要求
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。

输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door

点击下载参考ppt:《电梯运行过程详解》

Source Monitor分析结果:

  • 分析问题:上述图片数据表明我的代码方法逻辑复杂、代码冗长,尤其是主方法承担了过多功能(如电梯调度、请求处理等),未将功能拆分到不同类与方法中,不利于理解与维护并且注释过少,代码逻辑缺乏必要解释,可读性差,很可能使他人难以快速理解代码功能,因此由于我的代码复杂度太高导致始终在pta里面运行超时,未能在规定时间内完成题目,通过测试点。

第二次NCHU_单部电梯调度程序(类设计)

点击查看题目详细要求
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,具体设计可参考如下类图。
电梯迭代1类图.png
电梯运行规则与前阶段单类设计相同,但要处理如下情况:

乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
注意:本次作业类设计必须符合如上要求(包含但不限于乘客请求类、电梯类、请求队列类及控制类,其中控制类专门负责电梯调度过程),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次电梯程序提交到本次题目中测试)。

输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
📷 点击查看参考类图

类图说明

  • Controller类持有ElevatorRequestQueue对象,负责调度逻辑
  • RequestQueue通过分离内部/外部请求实现单一职责原则
  • 方向控制由Direction枚举类实现(UP/DOWN/IDLE)

Source Monitor分析结果:

  • 分析问题:由上述图片数据表明尽管 “Classes and Interfaces” 为 5,但主方法依然复杂,说明我的代码类间职责划分不够彻底。例如,电梯的状态管理、请求队列处理、调度算法等功能可能未完全独立到对应的类(如电梯类、队列类、控制类)中,导致 Main 类仍需处理大量核心逻辑,未充分体现单一职责原则的优势,并且代码注释仍然匮乏,需进一步优化类间职责划分,简化主方法逻辑,并补充注释以提升代码可读性与可维护性。

第三次NCHU_单部电梯调度程序(类设计-迭代)

点击查看题目详细要求
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考如下类图。
类图.png
电梯运行规则与前阶段相同,但有如下变动情况:

乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
注意:本次作业类设计必须符合如上要求(包含但不限于设计电梯类、乘客类、队列类以及控制类),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次及第二次电梯程序提交到本次题目中测试)。

输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
📷 点击查看参考类图

主要改进

  • 引入Passenger类解耦请求来源与目标
  • RequestQueue通过LinkedList<Passenger>管理请求队列
  • ControllerprocessRequests方法复杂度显著降低

Source Monitor分析结果:

  • 分析问题:由上述图片数据表明代码分支语句占比高:“Percent Branch Statements” 为 20.7 ,较高的分支语句占比意味着代码中条件判断较多 ,逻辑复杂,这可能导致我的代码难以理解和维护。

  • 第二点就是:方法复杂度高:“Maximum Complexity” 为 11 ,“Average Complexity” 为 2.48 ,且 “Line Number of Most Complex Method” 高达 93 行(对应方法为 “RequestQueue.getNextTarget ()” ) 。这些数据都说明我的代码存在复杂度过高的方法,这不仅使方法本身难以读懂、调试,也不利于代码的可维护性与可扩展性。

  • 第三点:最大块深度大:“Maximum Block Depth” 为 5 ,较深层的代码块嵌套会使代码逻辑结构混乱,理解代码执行流程难度增加。

  • 第四点:代码可读性方面注释比例极低:“Percent Lines with Comments” 仅为 1.0 ,意味着我的代码中注释极少。缺乏注释会让其他人(甚至自己一段时间后)难以快速理解代码功能、逻辑意图,严重影响代码可读性和可维护性。

  • 第五点:类与接口数量及方法分布:“Classes and Interfaces” 为 6 ,“Methods per Class” 为 3.83 。虽然类的数量不算少,但方法在类中的分布可能不够合理,可能存在部分类承担过多职责,未充分遵循单一职责原则。

三、心路历程及感悟

  • 在完成这三次 Java 电梯调度程序的迭代设计过程中,我收获颇丰,也经历了许多的挑战与成长。当我第一次设计电梯类时,我面临着诸多困惑与难题。首先我要考虑电梯的各种属性和运行规则,从最大最小楼层、当前楼层到运行方向和状态,还有请求队列的管理,这些复杂的逻辑让我感到无从下手。在编写代码时,常常写一段代码而没有考虑到全部的代码,导致代码逻辑混乱。不过,通过不断地调试和参考资料,我逐渐理清了思路,完成了基本的电梯调度程序。这让我深刻体会到了编程需要耐心和细心,每一个细节都可能影响整个程序的运行。

  • 当我做第二次迭代设计作业时,题目要求遵循单一职责原则,将电梯类的职责进行分离,设计了乘客请求类、队列类和控制类。这对我来说是一个全新的挑战,因为要重新思考类与类之间的关系和交互。当我一开始写这个题目时,我对如何划分职责感到迷茫,但通过深入学习单一职责原则,我逐渐明白了每个类应该承担的责任。这个过程让我认识到了良好的类设计可以提高代码的可维护性和可扩展性,也让我更加注重代码的架构和设计模式。

  • 而第三次迭代设计加入了乘客类,取消了乘客请求类,并且外部请求的输入格式发生了变化。这要求我对之前的代码进行大规模的修改。在面对这些需求变动时,我起初有些慌乱,但很快冷静下来,分析需求的变化点,逐步对代码进行调整。通过这次迭代,我学会了如何灵活应对需求的变化,也明白了在编程过程中要保持代码的灵活性和可扩展性。

四、总结

知识收获

  • 通过这三次题目集的系统性训练,我收获到了很多知识,从而进一步加深了对Java这门课程的认识,首先,通过验证码校验和QQ号校验2个题目,我初步地掌握了正则表达式,我明白了正则表达式不是写.*的玄学,而是精密的状态机。

  • 接着通过点与线的类设计,汽车风挡玻璃雨刷问题,销售步枪问题,特卡罗方法求圆周率等训练,我逐渐学会了合理设计类及其关系,这一阶段的三个题目集像是一套组合拳,把我们从能跑就行的代码民工,逐渐进化成了开始画类图的设计思考者。我逐渐领悟了什么叫做“类设计必须符合单一职责原则(SRP)”,逐渐明白了面向对象编程的概念,面向对象编程(OOP)就好比开家餐厅分工合作,而面向过程编程(POP)就好比跟着菜谱做菜。

  • 通过这三次题目集的锻炼,我很好的提升了逻辑思维,编程能力也得到了显著提示,心性也得到了良好的锻炼。

努力方向

  • 通过参与这三次 Java 电梯调度程序的训练题目集,我深刻认识到自己在多个方面存在不足,需要进一步学习和研究。
    虽然我已经了解了单一职责原则,但在实际应用中还不够熟练。在设计电梯调度程序时,仍然会出现类职责过多的情况。例如,电梯类原本承担了过多的功能,包括状态管理、请求队列管理以及调度算法等,导致代码的可维护性和可扩展性较差。我需要深入学习面向对象设计原则,掌握如何将不同的功能合理地分配到不同的类中,使每个类只负责单一的职责,从而提高代码的质量。

  • 在处理电梯调度问题时,调度算法的设计至关重要。目前我所实现的算法还比较简单,在处理复杂情况时效率较低。例如,在处理大规模随机数生成的蒙特卡罗仿真时,计算效率有待提高。我需要学习更多的算法知识,如搜索算法、排序算法等,并将其应用到实际问题中,以优化电梯调度算法,提高程序的性能。

  • 在处理乘客请求时,需要对输入进行严格的验证,以确保程序的健壮性。目前我在处理无效请求时,还不够完善。例如,对于乘客请求楼层数有误或请求不合理的情况,虽然已经实现了基本的过滤功能,但在处理异常情况时还不够细致。我需要学习如何进行全面的异常处理,包括输入验证、边界检查等,以确保程序能够正确处理各种异常情况。

  • 在编写代码的过程中,我发现自己缺乏代码复用和模块化设计的意识。例如,在不同的题目集中,有些功能是重复的,但我没有将其封装成可复用的模块,导致代码冗余。我需要学习如何进行代码复用和模块化设计,将常用的功能封装成独立的模块,提高代码的可维护性和可扩展性。

  • 总之,通过这三次训练题目集,我认识到自己在 Java 编程方面还存在很多不足之处。在今后的学习中,我将针对这些问题进行深入学习和研究,不断提高自己的编程能力。

对教学的改进建议

  • 对教学及实验的建议: 教师教学时可以再系统性一点,系统性讲解一些知识点,给予学生系统性的训练,做到前置知识巩固与衔接,在讲解面向对象设计原则(如单一职责原则)时,建议以电梯调度程序为例,通过逐步拆解类设计(如将电梯类、乘客类、队列类分离),直观展示如何将复杂功能分配到不同类中。例如,在课堂上对比初始单类设计与迭代后的多类设计,分析代码复杂度和可维护性的差异,帮助学生理解 SRP 原则的实际应用。做实验的时间可以稍微长一点,老师的实验系统可以再优化完善一下。

  • 对作业的建议:分阶段作业设计
    将复杂的电梯调度作业分解为基础功能→类设计→算法优化三个阶段。例如:
    阶段 1:实现电梯的基本运行逻辑(如楼层移动、开关门);
    阶段 2:引入乘客类和队列类,优化类结构;
    阶段 3:加入调度算法优化(如优先处理同方向请求)。
    通过逐步引导,降低学习压力,同时强化模块化设计能力。

  • 建议增加适当的学生学习反馈
    可以定期发放匿名问卷,收集学生对课程进度、作业难度、实验安排的意见,并根据反馈调整教学节奏。例如,若多数学生反映某类设计问题集中,可增加针对性的习题或辅导课程。

posted @ 2025-04-17 10:48  Gin殇  阅读(101)  评论(2)    收藏  举报