面向对象第一次blog
题量和难度
第一次
5题 中
第二次
3题 高
第三次
3题 高
知识点
数据结构与算法
列表(List): ArrayList被用来存储内部和外部请求,这允许动态添加和删除元素,非常适合用于存储楼层请求。
正则表达式: 在Main类中,使用了正则表达式来验证输入格式是否正确,确保只有符合特定模式的请求才会被处理。
面向对象编程
枚举类型: 用于表示电梯的运行方向。
封装: Elevator类封装了电梯的所有属性(如最小楼层、最大楼层、当前楼层等)和行为(如移动电梯、确定运行方向、处理请求等),体现了良好的封装性原则。
构造函数: Elevator类的构造函数初始化了电梯的基本属性,并设置了默认状态。
输入输出
Scanner: 在Main类中使用Scanner对象读取用户的输入,直到遇到“End”为止。这种方法可以灵活地接受不同长度的输入数据。
控制台输出: 使用System.out.println()打印电梯的状态变化信息,如当前楼层、运行方向以及开门关门的动作,便于调试和演示。
逻辑控制
循环与条件语句: 代码中大量使用了循环和条件语句来模拟电梯的运行逻辑,包括根据请求调整电梯的方向、判断电梯何时停止等。
方法调用: processRequests()方法负责调度电梯的运行流程,它通过不断调用move()方法使电梯上下移动,并在适当时候停下以响应乘客的需求。
设计和分析
类分布图

设计思路分析
合作关系
用户输入处理:在Main类中,通过Scanner对象读取用户的输入,并根据输入格式(内部或外部请求)将请求添加到Elevator实例中相应的请求队列里。
Scanner scanner = new Scanner(System.in);
List<String> inputList = new ArrayList<>();
String input;
// 读取用户输入的数据
while (!(input = scanner.next()).equalsIgnoreCase("End")) {
inputList.add(input);
}
电梯状态管理:Elevator类负责维护电梯的状态信息,如当前楼层、运行方向等,并依据接收到的请求更新这些状态。例如,在processRequests()方法中,电梯根据当前状态决定下一步行动,这展示了状态管理和请求处理的合作。
public void processRequests() {
System.out.println("Current Floor: " + currentFloor + " Direction: " + currentDirection);
// 当内部请求队列或外部请求队列不为空时,继续处理请求
while (!internalRequests.isEmpty() || !externalRequests.isEmpty()) {
// 调用 move 方法让电梯移动
move();
}
}
请求队列管理:无论是来自电梯内部还是外部的乘客请求,都被收集到Elevator类中的两个列表——internalRequests和externalRequests。这两个列表共同决定了电梯的下一步动作,突显了请求队列与电梯行为之间的紧密联系。
核心功能
- 电梯调度算法:该系统的调度算法主要体现在如何选择下一个目标楼层以及何时改变运行方向。
determineDirection()方法根据当前请求队列来决定电梯的运行方向,优先考虑同方向的请求,只有当所有同方向请求完成后才会转向相反方向。这是确保高效服务的关键所在。
int targetFloor = -1;
// 获取目标楼层
if (!internalRequests.isEmpty()) {
targetFloor = internalRequests.get(0);
} else if (!externalRequests.isEmpty()) {
targetFloor = externalRequests.get(0).getFloor();
}
if (targetFloor != -1) {
// 根据当前方向和目标楼层调整方向
if (targetFloor < currentFloor) {
currentDirection = Direction.DOWN;
} else if (targetFloor > currentFloor) {
currentDirection = Direction.UP;
}
}
- 动态调整方向:电梯不仅能够响应新的请求,还能根据当前队列情况动态调整其运行方向,比如在完成所有上行请求后开始处理下行请求。这种灵活性提高了系统对变化需求的适应能力。
- 处理顺路请求:当电梯朝某个方向移动时,它会检查是否可以在不偏离原定路线的情况下顺便处理其他请求(无论是内部还是外部)。这通过
shouldStop()及其辅助方法实现,使得电梯能够在满足更多乘客需求的同时减少不必要的停顿次数。
调度方式
优先级调度:对于外部请求,如果当前有多个乘客等待且他们的方向一致,则电梯会优先处理那些与当前运行方向相同的目标楼层请求。这样可以最大化利用一次行程,提高效率。
就近原则:无论是在处理内部还是外部请求时,电梯都会先前往距离最近的目标楼层。例如,如果有两个请求分别位于上方和下方,而电梯目前处于中间位置,则会选择先去较近的那个楼层。
开门关门机制:每当电梯到达一个包含请求的楼层时,它会自动开门让乘客上下车,然后关门继续前往下一个目的地。这一过程通过输出“Open Door # Floor X”和“Close Door”来模拟,确保了流程的真实性和完整性。
采坑心得
一开始并不知道直接读取<3,UP>,然后分类处理
代码如下
for (int i = 2; i < inputList.size(); i++) {
String request = inputList.get(i);
request=request.substring(1,request.length()-1);
String[] parts =new String[3];
parts[0]=request.substring(0,1);
if(request.contains(","))
{
parts[1]=request.substring(2,request.length()-1);
floor=parseInt(parts[0]);
direction=parts[1];
}
else
{
floor=parseInt(parts[0]);
}
}
发现无法运行,思考之后理解到应该是方法有局限性,应该用正则表达式等具有普适性的代码来书写
然后思考使用正则表达式,一开始正则表达式如下
if (request.contains(",")) {
// 检查请求格式是否正确
// 解析请求中的楼层和方向
String[] parts = request.replaceAll("[<>]", "").split(",");
int floor = Integer.parseInt(parts[0].trim());
Direction direction = Direction.valueOf(parts[1].trim().toUpperCase());
// 将外部请求添加到电梯的外部请求队列中
elevator.addExternalRequest(floor, direction);
}
// 否则是内部请求
else {
// 解析请求中的楼层
int floor = Integer.parseInt(request.replaceAll("[<>]", ""));
// 将内部请求添加到电梯的内部请求队列中
elevator.addInternalRequest(floor);
}
发现好像无法处理错误输入的情况,分析了一下后发现应该补充分支
最后修改如下
for (int i = 2; i < inputList.size(); i++) {
String request = inputList.get(i);
// 如果请求中包含逗号,说明是外部请求
if (request.contains(",")) {
// 检查请求格式是否正确
if (!request.matches("<\\d+,\\s*(UP|DOWN)>")) {
System.out.println("Wrong Format");
} else {
// 解析请求中的楼层和方向
String[] parts = request.replaceAll("[<>]", "").split(",");
int floor = Integer.parseInt(parts[0].trim());
Direction direction = Direction.valueOf(parts[1].trim().toUpperCase());
// 将外部请求添加到电梯的外部请求队列中
elevator.addExternalRequest(floor, direction);
}
}
// 否则是内部请求
else {
// 检查请求格式是否正确
if (!request.matches("<\\d+>")) {
System.out.println("Wrong Format");
} else {
// 解析请求中的楼层
int floor = Integer.parseInt(request.replaceAll("[<>]", ""));
// 将内部请求添加到电梯的内部请求队列中
elevator.addInternalRequest(floor);
}
}
}
改进建议
1. 数据结构的选择
在当前实现中,内部请求队列使用了ArrayList,这在处理大量请求时可能不是最优选择。对于频繁的插入和删除操作,LinkedList可能会提供更好的性能。然而,在这里我们更关心的是访问速度而非插入删除效率,因此保持ArrayList是合理的。但是,考虑到电梯请求的排序性质,可以考虑使用TreeSet或PriorityQueue来代替列表,以便能够高效地获取最小或最大楼层的请求。
2. 减少重复计算
在determineDirection()方法中,每次调用都会重新扫描整个请求队列以找到目标楼层。这可以通过维护一个指向下一个待处理请求的指针来避免,从而减少不必要的遍历次数。
3. 提高代码可读性与模块化
将逻辑复杂的方法如handleExternalRequests()拆分成更小、更具描述性的函数可以帮助提高代码的可读性和维护性。例如,可以创建单独的方法来检查外部请求是否符合当前方向条件,以及清除匹配的外部请求等。
4. 简化条件判断
在某些情况下,如handleExternalRequests()中的条件判断过于冗长且难以理解。简化这些逻辑不仅能让代码更简洁,也能降低出错的风险。
总结
通过对电梯模拟系统代码的学习和优化过程,我获得了许多宝贵的编程经验和知识。这些经验不仅加深了我对数据结构、算法优化、代码组织等核心编程概念的理解,还让我认识到在软件开发中遵循良好实践的重要性。
首先,在数据结构的选择上,我学到了不同的集合类型各自的特点及其适用场景。例如,ArrayList适用于需要快速随机访问元素的场景,而LinkedList则更适合频繁地进行插入和删除操作。对于排序需求较高的情况,TreeSet提供了自动排序的功能,而PriorityQueue可以用来实现优先级队列,确保每次都能从队列中取出最高优先级的元素。理解每种数据结构的优点和局限性,可以帮助我们在设计程序时做出更加合理的选择,从而提高程序的效率和性能。
其次,减少重复计算是提高程序性能的一个重要方面。原始的determineDirection()方法存在一个明显的不足:每次调用都会遍历整个请求队列来寻找目标楼层,这导致了大量的重复计算,尤其是在请求队列较大时,这种做法会显著降低程序的执行效率。通过引入缓存机制或预处理步骤,我们可以有效避免不必要的重复计算,大大提升程序运行速度。这提醒我们,在编写代码时应该时刻注意识别并消除潜在的性能瓶颈。
再者,提高代码的可读性和模块化是非常重要的。将复杂的方法拆分成多个小函数不仅可以让代码变得更加清晰易懂,也方便了后续的维护和扩展。良好的代码组织方式使得其他人(甚至是未来的自己)更容易理解和修改代码,这对于团队合作尤为重要。此外,采用一致的命名规则和注释习惯也是提高代码可读性的关键因素。
系统的深入研究让我深刻体会到了良好的编程习惯的重要性。从选择合适的数据结构到优化算法,再到注重代码风格和异常处理,每一个环节都对最终产品的质量有着直接的影响。例如,在异常处理方面,合理的错误捕获和处理机制不仅能提高程序的健壮性,还能为用户提供更好的使用体验。作为一名计算机专业的学生,这些经验无疑为我今后的学习和工作打下了坚实的基础。
关于进一步学习及研究的方向,我认为可以在以下几个方面进行探索:
算法优化:深入学习高级算法和数据结构,如图论算法、动态规划等,以解决更复杂的实际问题。
软件工程最佳实践:了解更多的软件开发流程和工具,如版本控制系统、持续集成/部署等,有助于提高项目管理能力和团队协作效率。
总之,这段学习经历不仅是对我编程技能的一次全面提升,也为我指明了未来努力的方向。在未来的学习和工作中,我将继续保持对新技术的好奇心和探索精神,不断提升自己的专业水平。
浙公网安备 33010602011771号