题集电梯
题集五:
相关知识点:
类与对象
类的定义:定义了 Elevator 类和 Main 类。Elevator 类封装了电梯的各种属性(如最小楼层、最大楼层、当前楼层、运行方向、运行状态等)和方法(如添加请求、处理请求、开门、关门等);Main 类作为程序的入口,负责读取用户输入并调用 Elevator 类的方法来模拟电梯运行。
数据结构
队列(Queue):使用 LinkedList 实现了 Queue 接口,用于存储电梯内部乘客的请求队列 insideRequests、电梯外部上行请求队列 upOutsideRequests 和电梯外部下行请求队列 downOutsideRequests。队列遵循先进先出(FIFO)的原则,适合用于处理依次到来的请求。
输入输出处理
输入读取:使用 Scanner 类从标准输入读取用户输入,包括最小楼层、最大楼层和乘客请求。通过 nextInt() 读取整数,nextLine() 读取一行字符串,并对输入进行解析和处理。
输出打印:使用 System.out.println() 方法将电梯的运行状态和操作信息输出到控制台,如当前楼层、运行方向、开门和关门提示等。
条件判断与循环
条件判断:在处理请求和判断电梯运行方向时,使用了 if-else 语句进行条件判断。例如,在 addInsideRequest 和 addOutsideRequest 方法中,判断请求的楼层是否在有效范围内;在 processRequests 方法中,根据请求队列的状态和电梯的当前方向决定下一步的操作。
循环结构:使用 while 循环处理多个请求,直到所有请求都被处理完毕。
字符串处理
字符串解析:在处理用户输入时,需要对输入的字符串进行解析。例如,通过 input.substring(1, input.length() - 1) 去除字符串两端的 < 和 >,通过 input.split(",") 将字符串按逗号分割成多个部分,从而获取楼层和方向信息。
异常处理(隐式)
程序中虽然没有显式的异常处理代码,但在输入处理过程中,如 Integer.parseInt(input) 可能会抛出 NumberFormatException 异常。在实际应用中,可以添加异常处理代码来增强程序的健壮性。
刚开始着手时,我就意识到要先把电梯类的整体架构搭建好,这就需要清晰地定义电梯的各种属性和方法。我认为定义电梯的属性相对容易理解,像最大楼层数、最小楼层数、当前楼层这些,很直观。但在考虑运行方向和运行状态的时候,还是费了一些心思。我仔细思考了电梯可能出现的状态,比如停止、移动中、开门、关门等,以及方向可能是上行、下行或者空闲状态。
调度算法部分是整个程序中最难的地方。我要实现电梯优先处理同方向的请求,并且在移动过程中处理顺路的请求。这涉及到复杂的逻辑判断和循环控制。我花了大量的时间来设计和完善这个算法,不断地在纸上模拟电梯的运行过程,然后将这些思路转化为代码。我通过学习,学会了如何根据电梯的当前状态和请求队列的情况,使用 if-else 语句和 while 循环来控制电梯的运行方向和停靠楼层。这个过程虽然艰难,但让我对条件判断和循环结构的运用更加熟练了。
在处理输入输出时,我也遇到了一些小问题。要从键盘读取用户输入,并对输入进行解析和验证,确保输入的格式和内容是有效的。这需要对字符串进行处理,使用 substring 和 split 方法来提取有用的信息。我一开始对这些字符串处理方法不太熟悉,通过查阅文档和不断实践,我逐渐掌握了它们的使用技巧,现在能够轻松地处理各种输入情况了。
题集六:
知识点:
1.单一职责原则(SRP):代码将不同的功能模块拆分成多个类,每个类只负责单一的职责。例如,PassengerRequest 类专门封装乘客请求信息;Elevator 类管理电梯的基本属性和状态操作;RequestQueue 类负责请求队列的管理;ElevatorController 类进行电梯调度和请求处理;Main 类负责输入读取和对象初始化。这种设计提高了代码的可维护性和可扩展性。
类与对象:定义了多个类,并通过创建对象来实现具体功能。
2. 类的设计与实现
属性封装:各个类中的成员变量大多使用 private 修饰,通过 getter 和 setter 方法进行访问和修改,实现了数据的封装,提高了数据的安全性。例如,Elevator 类中的 minFloor、maxFloor 等属性。
构造方法:每个类都有自己的构造方法,用于对象的初始化。例如,Elevator 类的构造方法接收 minFloor 和 maxFloor 参数,对电梯的基本属性进行初始化。
方法设计:类中定义了各种方法来实现不同的功能。如 Elevator 类的 moveUp、moveDown、openDoor 和 closeDoor 方法,分别实现电梯的上行、下行、开门和关门操作;ElevatorController 类的 processRequests、processUpRequests 和 processDownRequests 方法,负责处理请求和调度电梯。
3. 数据结构与集合框架
LinkedHashSet 的使用:RequestQueue 类使用 LinkedHashSet 存储 PassengerRequest 对象,LinkedHashSet 可以保证元素的插入顺序,并且自动去除重复元素,有效地处理了连续相同请求的问题。
Iterator 迭代器:在 ElevatorController 类中,使用 Iterator 迭代器遍历 LinkedHashSet 中的请求,便于在遍历过程中移除元素,避免了 ConcurrentModificationException 异常。
4. 输入输出处理
Scanner 类:Main 类使用 Scanner 类从标准输入读取用户输入,包括最小楼层、最大楼层和乘客请求信息。通过 nextInt() 读取整数,nextLine() 读取一行字符串,并对输入进行解析和处理。
System.out.println 输出:在电梯运行过程中,使用 System.out.println 方法将电梯的运行状态和操作信息输出到控制台,如当前楼层、运行方向、开门和关门提示等。
5. 异常处理与验证
楼层有效性验证:在 Elevator 类中提供了 isValidFloor 方法,用于判断请求的楼层是否在有效范围内。在 Main 类中添加请求时,会调用该方法进行验证,忽略无效楼层的请求。
异常处理(隐式):虽然代码中没有显式的异常处理代码,但在输入处理过程中,如 Integer.parseInt(input) 可能会抛出 NumberFormatException 异常。
6. 重写方法
equals 和 hashCode 方法:PassengerRequest 类重写了 equals 和 hashCode 方法,这是为了让 LinkedHashSet 能够正确判断两个 PassengerRequest 对象是否相等,从而实现去除重复请求的功能。
一开始,我拿到需求,知道要遵循单一职责原则,把原来职责过多的电梯类拆分成多个类。我仔细分析了类图和具体要求,确定了要设计 PassengerRequest、Elevator、RequestQueue 和 ElevatorController 这几个关键类。我觉得这就像是盖房子,得先把蓝图规划好,每个类负责的功能就像房子的不同房间,得明确它们各自的用途。
我首先着手编写 PassengerRequest 类,这个类主要是封装乘客的请求信息。定义属性的时候比较顺利,但是重写 equals 和 hashCode 方法让我犯了难。我知道这两个方法对于后续使用 LinkedHashSet 去除重复请求很关键,但是具体的实现逻辑有点复杂。我查阅了很多资料,学习了 equals 方法要比较对象的属性是否相等,hashCode 方法要根据属性生成一个唯一的哈希码。经过反复尝试和调试,我终于写对了这两个方法,当时心里别提多有成就感了,感觉像是解开了一道难题。
接着是 Elevator 类,它负责管理电梯的基本属性和状态操作。这个类的设计相对比较直观,我按照电梯的实际运行情况,定义了最小楼层、最大楼层、当前楼层、运行方向和状态等属性,还实现了电梯的移动、开门、关门等方法。不过,在编写 isValidFloor 方法时,我还是思考了一下边界条件,确保能正确判断请求的楼层是否有效。完成这个类的时候,我感觉电梯的基本框架已经搭建起来了,就像房子的主体结构已经完工。
RequestQueue 类让我又遇到了挑战。我选择使用 LinkedHashSet 来存储乘客请求,因为它可以保证元素的插入顺序,还能自动去除重复元素。但是我对 LinkedHashSet 的使用不是很熟悉,一开始不知道怎么把 PassengerRequest 对象正确地添加到集合中。我通过阅读 Java 文档和参考一些示例代码,逐渐掌握了 add 方法和 get 方法的使用,最终实现了请求队列的管理功能。这个过程让我对 Java 集合框架有了更深入的理解。
ElevatorController 类是整个程序的核心,负责电梯的调度和请求处理。这里的逻辑比较复杂,需要根据电梯的当前方向处理上行和下行请求。我在编写 processRequests、processUpRequests 和 processDownRequests 方法时,花了很多时间来设计算法。我先在纸上画出了电梯运行的流程图,然后根据流程图来编写代码。在处理请求的过程中,还需要使用 Iterator 迭代器来遍历请求集合,并且在遍历过程中移除已经处理的请求。这个过程中我遇到了 ConcurrentModificationException 异常,经过一番排查,我才知道在使用迭代器遍历集合时不能直接使用集合的 remove 方法,而要使用迭代器的 remove 方法。解决这个问题后, 我感觉自己对 Java 集合的操作又有了新的认识.
最后是 Main 类,它的主要任务是读取用户输入,创建相关对象并启动电梯调度。使用 Scanner 类读取输入相对简单,但是在解析输入时,要根据输入的格式判断是内部请求还是外部请求,并且调用相应的方法添加到请求队列中。同时,还要对输入的楼层进行有效性验证,忽略无效的请求。完成这个类后,整个程序就基本成型了。
代码编写完成后,我进行了大量的测试,使用不同的测试用例来模拟各种请求顺序。在测试过程中,我发现了一些小问题,比如输出格式不符合要求,或者某些边界条件没有处理好。我通过仔细检查代码和调试,逐步修复了这些问题,让程序的运行更加稳定和符合预期。