24201821-黄俊强-第一次blog作业

面向对象程序设计课程的第5-7次题目集结束了,其中让我们进行电梯系统代码不断增加新的功能,我学到了很多:

熟悉了Java基本语法;
初步建立起了面向对象的设计思路;
认识到了代码可拓展性的重要;
学会了构建自动化测试工具。
一,前言:
对于本次作业的知识点有:1.运用枚举类型Enum包括电梯Direction以及电梯状态State,这样可以限定取值范围,使代码更具可读性和维护性,标识电梯当前所处状态,方便系统逻辑判断以及在电梯系统中明确表示运行方向状态。2.每一个类class中都有各自的构造方法其中就有数据的传递与保存等知识,同时还有对于属性的初始化。3.getter和setter两个最基本的方法的使用,它们贯穿了电梯中的每一个类,因为在面向对象设计中需要考虑数据安全与保护防止非法访问与修改和降低数据被破坏的风险所以会将每个对象用private进行定义来实现信息隐藏与封装,所以数据的更新与取出需要用到getter与setter。4.方法重载的使用:在类中构造函数需要用到方法重载,这可以使代码可读性更强。5.ArrayList类的使用,在存储数据时,需要使用arraylist其中add方法以及getfirst进行处理数据。6.类鱼类之间的关系关联关系和依赖关系,思路提供:一个类可以作为另一个类的成员变量。7.逻辑思维中分类讨论思想:电梯最难的知识点在于处理请求,电梯移动时的分类。
对于本次实验题量与难度:我认为题量与难度在这三次的迭代中名没有太明显的区别,最主要的是优化了面向对象设计中单一职责的要求,以及低耦合。
1.第五次作业电梯
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。

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

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

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
当时做不出的地方
1、main函数中最主要的内容录入不会;
2、电梯太多类,不知道各个类的关系及建立;
3、电梯的各个类中,方法不会写;
4、不会电梯的分类思想,电梯处理请求,电梯运动,电梯方向;
第六次电梯实验:

电梯运行规则与前阶段单类设计相同,但要处理如下情况:

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

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

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
在第五次实验基础上,自家开始解决一些问题:

  1. 数据输入:
    利用 ArrayList list = new ArrayList<>();
    和 String[] parts = request.replaceAll("[<>]", "").split(",");
    和int destinationFloor = Integer.parseInt(request.replaceAll("[<>]"
    来处理输入的格式问题,这也解决了我的第一个难点
    2.设计elevator和control类的基本框架:
    getter与setter基本方法
    构造方法的组建;
    这是开始进行电梯功能设计的开始
    但是远远不够解决电梯问题;
    第二次面临的问题
    1.电梯的内部请求和外部请求的处理(提取,清除,先后)
    2.电梯的运动(方向确定,移动如何实现,请求的删除)
    3.各类之间到底要用怎样的关系
    4.分类讨论
    第七次电梯设计

    电梯运行规则与前阶段相同,但有如下变动情况:

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

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

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
设计与分析
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:


行数(Lines):355 ,说明代码量不算少。
语句数(Statements):233 ,语句占比可反映代码密度。
分支语句占比(Percent Branch Statements):19.3% ,意味着近两成语句是分支逻辑,代码逻辑有一定复杂度。
方法调用语句数(Method Call Statements):115 ,反映方法间调用频繁程度。
注释行占比(Percent Lines with Comments):仅 0.3% ,注释严重不足,不利于代码理解维护。
结构与复杂度指标
类和接口数(Classes and interfaces):7 ,结构有一定规模。
每类方法数(Methods per Class):5.43 ,类的功能相对丰富。
平均方法语句数(Average Statements per Method):4.58 ,方法规模较小,可能是细粒度拆分,但也可能逻辑分散。
最复杂方法行号(Line Number of Most Complex Method):214 ,Controller.getNextFloor()方法复杂度最高,值为 36 ,需重点关注优化。

1、单一职责运用:
processRequests()
determineDirection(int q)
move(int floor)
shouldStop(int floor)
getNextFloor()
openDoors()
removeRequests(int currentFloor)
循环:
目标楼层(getNextFloor)->
确定方向(determinDirection)->
电梯移动(move)->
清除请求(removerequest)
2、优化心得:、
由于我并没有做出前两次实验,不能做对比,代码并无优化,
但在编写代码时,尤其是(确定下一个去哪)做到先不着急把一类考虑清楚;而是把大至框图描绘出来;
所以以后只需像这样将大类构建好,就不会产生分类不完全,导致代码出错。
移动时,不需要一次一动,而是确定了目标楼层时,直接while循环到一楼层:
while (elevator.getCurrentFloor() != floor) {
if (elevator.getDirection() == Direction.UP) {
elevator.setCurrentFloor(elevator.getCurrentFloor() + 1);
} else {
elevator.setCurrentFloor(elevator.getCurrentFloor() - 1);
}
System.out.println("Current Floor: " + elevator.getCurrentFloor() + " Direction: " + elevator.getDirection());
}
这样能减少代码运行时间,同时在运动后直接进行输出,简单明了。
类与职责说明:
passenger类:
getter与setter用于信息的封装;

elevator类:
getting与setting用于信息的封装;
isvalidfloor用于确认信息是否合理化;
control类:
getting与setting用于信息的封装;
processrequest用于调用其他控制指令,起到中枢作用;
determinDirection用于决定电梯方向,确认是向上运动还是向下运动;
move用于移动电梯,并起到输出作用;
getnextfloor用于获得下一个目标楼层,以确定上面三个的依据;
deleterequest用于删除请求,是程序停止的必要条件;

踩坑心得
1.在处理外部请求时,需要将外部请求加入内部请求队列中,我出现过由于调用了多次函数,导致出现数据重复
2.在处理开门关门时,也是由于在函数中也有个函数点用了oppendoor函数,导致会出现两次开门关门;(所以一定要思考哪里要调用哪里不要)
3.在处理移除外部请求时,由于没考与清楚,有时候直接return,导致没有移除已处理的请求,
而有时却重复两次,导致下一个请求也被移除;
4.处理电梯移动时,一开始采用一动一输出,这导致代码运行超时,所以我需要用while直接一步到位;
5.在处理方向是,只靠与UP和DOWN而忽视了静止状态,所以考虑不周全;
6.在处理getnextfloor时,也是由于,有时候电梯楼层等于外部请求,可是外部请求不一定会处理,这就导致还有一种情况没有考虑到(外部楼层肯等于电梯楼层);
7.在编译运行代码时,enum类的赋值需要用Direction.UP或Direction.DOWN,所以出现很多错误;
8.在需要用成员变量时,需要先写成员在加"."+成员的方法,有时忘记带前面成员变量的名字,导致运行时出现,该方法未定义的情况;
改进建议
1.代码注释完善:当前代码注释占比仅 0.3%,严重影响代码的可读性和可维护性。后续应在关键方法、复杂逻辑块以及类定义处添加详细注释,说明功能、参数含义和实现思路。例如,在Controller.getNextFloor()等高复杂度方法中,通过注释拆解逻辑步骤,帮助自己和他人快速理解代码意图。

2.优化条件分支结构:虽然分类讨论的方式有助于理清逻辑,但现有代码中部分条件分支嵌套过深(如getNextFloor方法),可通过提取公共逻辑、封装成独立方法,或采用策略模式简化代码结构,减少重复代码和嵌套层级,提升代码的可维护性和扩展性。

3.增强错误处理与日志记录:目前仅对无效楼层请求和重复请求进行了简单处理,可进一步完善异常处理机制。例如,在输入解析过程中捕获NumberFormatException等异常,通过日志记录错误信息,方便排查问题;对于非法输入,除忽略外,可输出提示信息,增强程序的友好性。

4.提升代码复用性:部分功能(如请求队列的处理、方向判断逻辑)在不同类或方法中存在重复实现。可将这些通用功能抽象成工具类或公共方法,减少代码冗余。例如,创建一个RequestUtil工具类,封装请求格式校验、请求队列操作等通用方法。

5.引入自动化测试优化:目前虽学会了构建自动化测试工具,但测试用例可能不够全面。后续应补充边界值测试(如最小 / 最大楼层请求、空请求队列等)、异常场景测试,通过自动化测试持续验证代码修改后的正确性,避免引入新的 Bug。
总结
1.学习收获

语法与设计能力提升:通过三次作业的迭代开发,熟练掌握了 Java 基础语法,包括枚举类型、方法重载、ArrayList等容器类的使用。同时,逐步建立起面向对象的设计思维,理解了类的封装、继承与多态,学会通过类的合理设计实现功能解耦,满足单一职责原则。
工程化思维培养:意识到代码可扩展性的重要性,在需求不断变化的过程中,学会通过模块化设计、低耦合的类关系(如关联关系和依赖关系)降低系统复杂度,为后续功能扩展奠定基础。此外,掌握了构建自动化测试工具的方法,提升了代码质量和开发效率。
问题解决与逻辑训练:在处理电梯请求调度的复杂逻辑中,强化了分类讨论、流程控制等思维能力。通过分析电梯运行规则、处理不同场景下的请求(如同向优先、无效请求过滤),锻炼了将现实问题抽象为代码逻辑的能力。

2.需进一步学习方向

设计模式深化应用:目前仅初步接触面向对象设计原则,未来可学习更多设计模式(如工厂模式、观察者模式),以更优雅地解决代码耦合、扩展性问题,提升系统架构设计能力。
多线程与并发编程:实际的电梯系统需处理并发请求,后续可学习 Java 多线程编程,研究如何通过线程安全的设计实现高效的请求调度,避免资源竞争和死锁问题。
代码性能优化:虽然通过循环优化减少了运行时间,但在复杂场景下,代码性能仍有提升空间。可学习算法优化、数据结构选择(如使用LinkedList替代ArrayList处理频繁增删操作)等知识,进一步提高程序运行效率。

3.对课程与教学的建议

增加设计案例引导:在作业布置前,可提供更多电梯系统设计的参考案例或 UML 类图示例,帮助学生更好地理解类之间的关系和功能划分,减少初期设计迷茫。
强化代码审查与反馈:建议增加代码互评或教师代码审查环节,针对学生代码中的设计缺陷、代码规范问题提供具体反馈,帮助学生认识不足并改进。
细化作业迭代说明:在每次作业迭代时,明确指出新增功能与原有代码的关联和修改点,避免学生因理解偏差重复造轮子或忽略重要逻辑调整。
拓展实践场景:除电梯系统外,可引入其他贴近生活的工程化案例(如停车场管理系统、图书馆借阅系统),让学生在多样化场景中巩固面向对象设计能力,提升综合实践水平。

posted @ 2025-04-19 21:16  zmkkjing  阅读(41)  评论(0)    收藏  举报