第一次Blog(电梯)
BLOG1
前言:在编程学习的道路上,面向对象编程是一座绕不开的重要里程碑。它以独特的思维方式,将现实世界中的事物抽象为程序中的对象,通过封装、继承和多态等特性,让代码更加模块化、可复用且易于维护。在一系列的编程实践项目中,我深入探索了面向对象的核心,并将其应用于解决从基础到复杂的各类实际问题,每一个题目都是一次对编程思维的深度锤炼。
从身份证校验码的计算,到电梯调度系统的迭代优化;从平面直角坐标系中图形类的构建,到汽车雨刷速度控制的逻辑实现,这些项目涵盖了算法设计、类的架构规划以及业务逻辑处理等多个方面。在这个过程中,我不仅学会了如何将复杂的需求拆解为清晰的类和方法,还深刻体会到遵循设计原则。它让代码的职责更加明确,避免了类的功能过于臃肿,从而提高了代码的可读性和可维护性。
接下来,我将详细分享在这些项目中的实践过程、遇到的挑战以及收获的宝贵经验,希望能与大家一同探讨面向对象编程的魅力与精髓,为编程学习之路提供更多的思考与启发。(每个题目集都是自己实打实敲出来的都是经历过熬夜的更改最终不负众望取得高分)
第五次作业
这次作业的要求是写一个傻瓜式调度的电梯,笔者也是按指导书去写的,整体写起来很轻松,也算入门了Java多线程的写法、共享对象的使用以及锁的使用。
代码规模

第一次的业务逻辑很清晰,就是一个简单的电梯测试,只需要弄懂电梯的运行逻辑,可以很简单地实现傻瓜电梯的功能,也不容易出bug。
复杂度分析


设计分析
PTA5 类:作为程序的入口点,负责读取用户输入,包括最小楼层、最大楼层和请求列表。将内部请求和外部请求分别存储在不同的 evaloter 对象中,然后调用 evaloter 对象的 action 方法处理请求。
evaloter 类:封装了电梯的相关属性(如最大楼层、最小楼层、当前方向、状态等)和操作方法。action 方法根据请求列表和当前楼层处理请求,调用 elevatorAction 方法模拟电梯的运行。getNumber 方法用于从请求字符串中提取楼层号,getOuterQueueDirection 方法用于获取外部请求的方向。
(一)代码结构与功能概述
本次作业实现了傻瓜式调度电梯。Main类负责读取输入,包括最小楼层、最大楼层以及乘客请求。evaloter类承担了电梯的核心逻辑,如设置电梯的运行参数、处理请求队列以及执行电梯的运行动作。通过正则表达式匹配输入请求,区分内部请求(<数字>)和外部请求(<数字,(UP|DOWN)>),并分别添加到相应队列。
(二)核心算法与逻辑实现
在action方法中,电梯根据当前状态(IDLE、UP、DOWN)以及内部和外部请求队列的情况来决定运行方向和停靠楼层。若处于空闲状态,优先处理内外请求楼层相同的情况;若内外请求楼层不同且方向一致,优先处理距离当前楼层较近且同向的请求;若方向相反,则根据具体情况选择先处理内部或外部请求。电梯运行过程中,通过elevatorAction方法输出电梯的运行轨迹和开关门动作。
踩坑心得
1.方向与状态判断:
代码中涉及到大量的方向(UP、DOWN、IDLE)和状态(STOPPED、MOVING)判断。这些判断逻辑复杂,容易出现逻辑错误。例如,在判断电梯是否应该改变方向或停止时,如果条件判断不准确,会导致电梯行为异常。
心得:在编写复杂的逻辑判断时,建议先画出流程图或状态转换图,理清思路,然后再编写代码。同时,要进行充分的单元测试,验证每个逻辑分支的正确性。
2.请求处理顺序:
处理内部请求和外部请求时,需要合理安排处理顺序。如果处理顺序不当,可能会导致电梯频繁改变方向或忽略某些请求。例如,在同时有内部和外部请求时,没有正确判断哪个请求更优先处理。
心得:在设计请求处理逻辑时,要明确优先级规则,并在代码中清晰地实现这些规则。
3.楼层边界
在处理电梯移动时,需要考虑楼层的边界条件,即最小楼层和最大楼层。如果没有正确处理边界条件,可能会导致电梯超出有效楼层范围。
心得:在电梯移动的逻辑中,添加对楼层边界的检查,确保电梯不会超出有效范围。
4.空请求队列
在处理请求队列时,需要考虑队列为空的情况。如果没有正确处理空队列,可能会导致空指针异常。
心得:在访问队列元素之前,先检查队列是否为空。
优点与不足
优点在于代码结构相对简单清晰,对于基本的电梯运行逻辑实现较为准确,能够快速实现傻瓜式调度功能。然而,不足之处也较为明显,代码缺乏良好的封装和扩展性,类的职责划分不够细致,例如evaloter类承担了过多功能,包括输入处理、调度逻辑和输出操作等。同时,没有考虑到多线程环境下可能出现的并发问题,代码在可维护性和健壮性方面存在提升空间。
第六次作业
本次作业的要求是写改进电梯,使电梯分类更符合Java的面向对象设计,便于后面的修改与阅读。这次作业的逻辑和上次的第五次作业的电梯一样不变只是将其分类。
代码规模

类图

第二次作业相比第一次作业,只增加了捎带需求,而为了适应多电梯的扩展,
将各个类的作用标注清楚,类的功能分清楚,各自实现自己的功能。
复杂度分析

设计分析
PTA6 类:程序的入口点,读取最小楼层、最大楼层和请求列表。创建 Elevator、RequestQueue 和 Controller 对象,过滤无效请求,将请求添加到请求队列中,最后调用 Controller 的 processRequest 方法处理请求。
Elevator 类:表示电梯,封装了电梯的属性(如当前楼层、最大楼层、最小楼层、方向、状态等)和相关的访问方法。
ExternalRequest 类:表示外部请求,包含请求的楼层和方向。
RequestQueue 类:管理内部请求和外部请求的队列,提供添加请求和获取请求列表的方法。
Controller 类:负责处理请求,根据请求队列和电梯的当前状态控制电梯的运行。processRequest 方法是核心处理方法,move 方法用于根据不同情况决定电梯的移动方向,elevatorAction 方法模拟电梯的运行过程。
(一)代码结构调整与新功能引入
相较于第五次作业,此次代码结构进行了优化。新增了Direction和State枚举类,使代码可读性增强。Elevator类负责管理电梯的状态和属性,RequestQueue类用于存储内部和外部请求,Controller类承担了请求处理和电梯运行控制的核心职责。作业引入了 ALS 调度算法(实际采用 Look 调度算法),并考虑了多电梯扩展的可能性。
(二)算法改进与线程安全考量
在Controller类的processRequest方法中,根据电梯当前方向和请求队列情况,采用 Look 调度算法决定电梯运行方向。例如,当电梯向上运行时,优先处理向上且楼层高于当前楼层的请求。为了避免死锁和确保线程安全,虽然代码中未显式使用锁机制,但通过合理的请求处理顺序和状态管理,在一定程度上保证了多线程环境下的正确性。同时,通过filterInvalidRequests方法对输入请求进行预处理,过滤掉无效请求,提高了程序的健壮性。
踩坑心得
1.类的功能分类不明确:
在分类内部与外部请求时,将其归为一个请求录入,最终在后面的调用时,出现程序的调用混乱,后面才在类图的分析中发现这一问题,并将其改为两个类(内部请求,外部请求)
代码质量提升与遗留问题
代码在结构和功能实现上有了显著提升,各组件职责更加明确,符合单一职责原则,提高了代码的可维护性和扩展性。不过,在修改的过程中发现之前的代码存在一些电梯运行的逻辑上的问题,并在这次中进行了修改,但不能保证这次的代码逻辑是否完全符合题目的逻辑,这次代码的主体逻辑依然庞大,若要修改则需花费相当大的时间,所以这次的代码问题为没能将主题代码逻辑进行细微分化为各个小块,后面的代码修改主题逻辑时需要重新构造修改。
第七次作业
最后一次作业只是在第二次电梯的基础上将外部请求中的方向改为目标楼层,并且将目标楼层排入内部请求的队尾。
代码规模

类图

可以看到,对于笔者的架构,从第二次作业到第三次作业,几乎只需要修改控制类,和外部请求类,所以作者这次作业完成地也比较轻松。
复杂度分析


设计分析
PTA7 类:程序的入口点,读取最小楼层、最大楼层和请求列表。创建 Elevator、RequestQueue 和 Controller 对象,过滤无效请求,将请求添加到请求队列中,最后调用 Controller 的 processRequest 方法处理请求。
Elevator 类:与 PTA6.java 中的 Elevator 类功能相同,封装了电梯的属性和访问方法。
Passenger 类:表示乘客,包含乘客的起始楼层和目标楼层,以及根据起始和目标楼层计算的方向。
RequestQueue 类:管理内部请求和外部请求的队列,使用 LinkedList 存储 Passenger 对象,提供添加请求和获取请求列表的方法。
Controller 类:与 PTA6.java 中的 Controller 类功能相似,负责处理请求,根据请求队列和电梯的当前状态控制电梯的运行。
(一)复杂功能实现与架构演进
本次作业实现了考虑换乘的复杂系统。代码在之前的基础上进一步扩展,Passenger类用于表示乘客请求,包含出发楼层和目的楼层。RequestQueue类对内部和外部请求队列的管理更加细化。Controller类的processRequest方法处理电梯环境下的请求分配和电梯运行调度,同时考虑了换乘请求的拆分和处理。
(二)换乘功能实现与多电梯协作
对于需要换乘的请求,在输入时将其拆分成两条指令。在Controller类中,通过判断请求楼层是否在电梯可到达范围内以及是否需要换乘,合理分配请求到相应电梯的请求队列。电梯在运行过程中,根据自身请求队列和当前状态,按照 Look 调度算法运行,与其他电梯协作完成乘客运输任务。
踩坑心得
第三次的电梯可谓最简单的一次,只需在第二次的类上将需要的加入,将不需要的删除,并在主题逻辑上替补即可,但是在替补上不能想当然的直接数据替换,而是需要将内部请求的目标楼层加入到外部请求中。
代码优化与挑战应对
代码针对电梯和换乘功能进行了全面优化,在复杂业务逻辑下保持了一定的代码可读性和可维护性。通过合理的类设计和方法组织,实现了多线程环境下电梯系统的高效运行。然而,由于功能复杂性却没有前几次复杂,只是在上一次的代码上更新迭代。
总结
(一)多线程编程能力提升
通过这三次电梯作业,我对多线程编程有了更深入的理解和实践经验。从最初对多线程概念的初步接触,到逐渐掌握如何在多线程环境下实现复杂的业务逻辑,如电梯的调度算法、请求处理等,我学会了合理分配线程任务、避免死锁以及确保线程安全。同时,通过不断优化代码结构和算法,提高了程序的性能和稳定性。
(二)软件设计原则的实践体会
在作业过程中,我深刻体会到软件设计原则的重要性。遵循单一责任原则,使每个类的职责清晰明确,提高了代码的可维护性和扩展性;在考虑系统扩展性时,努力遵循开放封闭原则,通过合理的架构设计和类的抽象,为系统增加新功能提供了便利。
(三)未来学习方向与目标
展望未来,我将继续深入学习多线程编程技术,研究更复杂的并发算法和设计模式,如线程池的应用、生产者 - 消费者模式的优化等,以进一步提升程序的性能和并发处理能力。同时,加强对软件设计原则的学习和应用,不断优化代码结构,提高代码质量。通过不断学习和实践,努力成为一名具备扎实编程基础和良好软件设计能力的开发者。
希望在以后的学习中,我可以更好地掌握测试方法,写出更加完美的程序。
浙公网安备 33010602011771号