题目集5~7的总结

前言

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

第五次题目集

本次题目集的题目分别为:
求身份证号校验位 、求解一元二次方程 、正则表达式训练-验证码校验 、正则表达式训练-QQ号校验 、单部电梯调度程序;

1. 知识点

主要知识点有(1).字符串处理(2).数组与循环(3).正则表达式(4).字符串转换为字符数组

2.题量

题量适中

3.难度

难度中等

第六次题目集

本次题目集的题目分别为:
点与线(类设计) 、汽车风挡玻璃雨刷问题(类设计) 、单部电梯调度程序(类设计)

1. 知识点

主要知识点有(1).字符串处理(2).数组与循环(3).正则表达式(4).字符串转换为字符数组(5).类设计

2.题量

题量较少

3.难度

难度中等

第七次题目集

本次题目集的题目分别为:
销售步枪问题 、 蒙特卡罗方法求圆周率 、单部电梯调度程序(类设计-迭代)

1. 知识点

主要知识点有(1).字符串处理(2).数组与循环(3).正则表达式(4).字符串转换为字符数组(5).类设计

2.题量

题量较少

3.难度

难度较难

设计与分析

(重点对题目的提交源码进行分析) (只分析三次题目集中的电梯题目)

第五次题目集

题目:单部电梯调度程序

image
image
指标项------数值------说明
类数量------2------Elevator + Main
方法总数------10------Elevator 类包含 8 个方法,Main 类 1 个方法
代码行数------~200------实际有效代码行数(不含空行和注释)
平均圈复杂度------4.2------较高复杂度方法:findNextFloor()(6)、determineDirection()(5)
注释比例------15% 方法级注释较完整,但部分逻辑块缺少说明
耦合度------低------仅依赖 java.util 和自定义 enum

关键结论:
核心逻辑集中在 Elevator 类,但 findNextFloor() 和 determineDirection() 方法复杂度较高,需考虑拆分。

类职责说明
Direction 枚举:定义电梯运行状态(上行、下行、空闲)。

OuterRequest 内部类:封装外部楼层请求(目标楼层+方向)。

Elevator 核心类:

属性:楼层范围、当前状态、内外请求队列。

方法:请求处理(addRequest)、调度逻辑(processRequests)、移动控制(moveToFloor)。

Main 类:处理输入输出,驱动电梯运行。

相应心得:
一、面向对象设计(OOP)的实践价值
封装与职责分离

将电梯状态(Direction)、请求(OuterRequest)等概念独立为类/枚举,避免全局变量污染。

Elevator 类内聚所有调度逻辑,对外仅暴露 addRequest() 和 processRequests() 方法,符合“高内聚低耦合”原则。

启示:OOP 能显著提升复杂逻辑的可维护性,尤其在状态机类场景(如电梯、订单流程)。

组合优于继承

使用 LinkedList 组合管理请求队列,而非继承 List 实现,保持灵活性。

反例:若强行用继承实现 PriorityQueue,会导致过度设计。

二、算法选择与性能权衡
SCAN 算法的适用性

当前实现类似电梯扫描算法(双向扫描),适合均匀分布的请求。

局限性:未考虑高峰期的请求密度差异(如早高峰大量上行请求)。

改进方向:可引入动态权重(如等待时间优先)或分区调度(如高层/低层分电梯)。

时间复杂度优化

findNextFloor() 的递归调用可能引发栈溢出(极端情况下)。

解决:改为循环结构,或预计算请求的最远目标楼层。

第六次题目集

image
image
指标------数值------健康度分析
类数量------5------职责分离良好(Controller/Queue/Elevator各司其职)
方法平均复杂度------2.1------最佳实践范围(1-3),仅shouldStop()方法复杂度为4需关注
代码行数------215------有效代码行数(不含空行/注释)
注释比例------18%------类/方法级注释完整,但部分复杂逻辑需补充行内注释
耦合度------0.3------低耦合设计(类间仅通过接口交互,无双向依赖)

相应心得:设计模式的价值

当前使用组合模式(Controller聚合子组件)比原版的单一类更易扩展

潜在改进:可引入观察者模式实现请求事件通知

测试驱动开发(TDD)的必要性

发现原版未处理"5,UP"和"5,DOWN"同时按下的冲突场景

测试用例建议:
@Test
void shouldPrioritizeSameDirectionRequests() {
controller.addRequest("3,UP");
controller.addRequest("5,DOWN"); // 应不被处理
assertEquals(3, elevator.getNextFloor());
}
性能与可读性的平衡

RequestQueue使用LinkedList适合低频请求,高频场景建议:

按楼层分桶:Map<Integer, Queue>

使用ConcurrentLinkedQueue支持多线程

架构演进方向

mermaid

graph LR
A[单电梯] --> B[多电梯协同]
B --> C[分布式调度]
C --> D[容错与降级]

image

类职责说明:

一、模型层(Model)

  1. PassengerRequest 乘客请求类
    核心职责:封装电梯请求的元数据

记录请求楼层(floor)

记录请求方向(direction,外部请求特有)

标识请求类型(isInternal,区分电梯内/外按钮)

关键方法:

equals():实现基于楼层+方向+类型的去重逻辑

设计思考:

使用不可变对象(字段final)保证线程安全

将方向与楼层绑定,符合物理世界逻辑("5楼向上按钮"是一个完整请求)

  1. RequestQueue 请求队列类
    核心职责:管理请求的生命周期

存储待处理请求(Queue

过滤无效/重复请求(通过lastRequest比对)

提供请求消费接口(getNextRequest())

关键设计:

输入标准化:addRequest()方法统一处理<5>和<5,UP>两种格式

隐式验证:自动丢弃越界楼层(floor < minFloor时静默过滤)

改进建议:

可扩展为优先级队列(如按等待时间排序)

二、控制层(Controller)

  1. ElevatorController 电梯控制器
    核心职责:协调电梯与请求队列的交互

接收原始输入并转发给RequestQueue(addRequest())

驱动电梯运行流程(run()方法的主循环)

工作流程:

mermaid

sequenceDiagram
Controller->>Queue: getNextRequest()
Queue-->>Controller: PassengerRequest
Controller->>Elevator: moveTo(request.floor)
Elevator->>Controller: 到达事件
Controller->>Elevator: openDoor()/closeDoor()
现存问题:

单线程顺序处理,无法实时响应新请求

  1. Direction 枚举
    核心职责:定义电梯运行状态

UP/DOWN:明确双向运行逻辑(相比原版去除IDLE更简洁)

设计亮点:

避免魔法字符串,增强类型安全(如Direction.valueOf("UP"))

三、设备层(Device)
Elevator 电梯实体类
核心职责:模拟物理电梯行为

移动控制(moveTo()逐层更新状态)

门控制(openDoor()/closeDoor())

停止判断(shouldStop()结合内外请求逻辑)

关键算法:

java

// 停止条件判断逻辑
public boolean shouldStop(PassengerRequest request) {
return request.getFloor() == currentFloor &&
(request.isInternal() || // 内部按钮无条件停止
direction == request.getDirection() || // 同向外部请求
isAtBoundaryFloor()); // 顶层/底层强制转向
}
优化方向:

引入状态模式(如MovingState/StopState)替代硬编码条件判断

四、入口层(Main)
Main 系统入口
核心职责:程序启动与IO处理

初始化电梯参数(minFloor/maxFloor)

创建控制器实例并传递输入

监听终止命令("end")

设计缺陷:

直接使用Scanner耦合IO实现,难以切换输入源

改进方案:

java

public static void main(String[] args) {
InputSource input = new ConsoleInput(); // 可替换为FileInput
new ElevatorSystem(min, max).start(input);
}
五、类间协作关系
mermaid

flowchart TB
Main --> ElevatorController
ElevatorController --> RequestQueue
ElevatorController --> Elevator
RequestQueue --> PassengerRequest
Elevator --> Direction

classDef model fill:#f9f,stroke:#333;
classDef ctrl fill:#bbf,stroke:#333;
classDef device fill:#f96,stroke:#333;

class PassengerRequest,RequestQueue model;
class ElevatorController ctrl;
class Elevator,Direction device;

协作原则:

单向依赖:上层(Main)可依赖下层(Controller),反之禁止

接口隔离:队列通过getNextRequest()暴露最小接口

迪米特法则:Elevator不知道RequestQueue的存在

六、设计模式应用总结
组合模式

ElevatorController聚合Elevator和RequestQueue

优点:可独立扩展队列算法或电梯型号

不变模式

PassengerRequest的不可变性保证线程安全

潜在扩展模式

策略模式:动态切换调度算法(SCAN/LOOK等)

观察者模式:实现电梯位置实时监控

第七次题目集

image
image
指标------数值------健康度评估
类数量------5------职责划分清晰(Passenger/RequestQueue/Elevator等)
方法平均复杂度------3.2------较v2版本上升(因引入双向队列和更复杂调度逻辑),findNextRequest()达6需重构
代码行数------280------核心逻辑行数(新增楼层间移动策略)
注释比例------15%------方法级注释完整,但复杂算法缺少行内说明
耦合度------0.4------中等耦合(ElevatorController需感知两种队列细节)
相应心得:

  1. 设计模式应用
    策略模式替换硬编码调度算法:

interface SchedulingStrategy {
Passenger findNextRequest(RequestQueue queue, Elevator elevator);
}
class LookStrategy implements SchedulingStrategy { ... }
状态模式管理电梯运行阶段:

interface ElevatorState {
void handleRequest(ElevatorContext context);
}
class MovingUpState implements ElevatorState { ... }
2. 性能优化
请求索引:使用TreeMap加速最近楼层查找

private NavigableMap<Integer, Passenger> upRequests = new TreeMap<>();
并行处理:分离IO线程与调度线程(需线程安全队列)

  1. 工程实践心得
    领域建模的精准性

发现Passenger既表示请求又携带行程信息,应拆分为:

classDiagram
class CallRequest { +floor +direction }
class RideRequest { +targetFloor }
Passenger *-- CallRequest
Passenger *-- RideRequest
测试驱动开发的必要性

边界用例测试(如同时按下3楼UP和5楼DOWN)

性能测试:千级请求压力下的调度延迟

可观测性增强

添加运行指标统计:

class Metrics {
int totalRequests;
double avgWaitTime;
void logRequest(Passenger p) { ... }
}
image

类职责说明:
Passenger类:

封装乘客信息:源楼层、目的楼层、是否为内部请求

提供方向计算方法

RequestQueue类:

管理两个队列:外部请求队列和内部请求队列

处理请求添加、重复请求过滤

处理外部请求完成后自动添加内部请求

Elevator类:

管理电梯状态:当前楼层、运行方向

实现电梯移动、开关门操作

判断是否应该在当前楼层停止

ElevatorController类:

协调电梯和请求队列

实现电梯调度算法

处理请求优先级和方向选择

采坑心得

(对源码的提交过程中出现的问题及心得进行总结)
一、开发过程中遇到的问题

  1. 初始设计阶段的问题
    问题1:类职责划分不清晰

最初版本将所有功能都放在Elevator类中,导致类过于庞大

调度逻辑、请求处理和电梯运行混杂在一起

违反了单一职责原则(SRP)

解决方式:

将系统拆分为Passenger、RequestQueue、Elevator和ElevatorController四个类

每个类只负责一个明确的职责

  1. 请求处理逻辑问题
    问题2:重复请求处理不当

最初没有正确处理连续的相同请求

导致电梯会在同一楼层多次停留

解决方式:

在RequestQueue类中添加lastRequest字段

比较新请求与上一个请求,过滤掉完全相同的请求

  1. 电梯调度算法问题
    问题3:方向选择策略不完善

初期版本在电梯空闲时方向选择不合理

有时会导致电梯来回"抖动"

解决方式:

实现更智能的方向选择算法

优先处理当前方向的请求,没有请求时才改变方向

  1. 外部请求转内部请求问题
    问题4:外部请求处理后未自动添加内部请求

最初版本没有实现题目要求的"外部请求处理后要将其目的楼层加入内部队列"

解决方式:

在RequestQueue类中添加completeExternalRequest方法

处理外部请求后自动创建对应的内部请求

二、架构设计心得

  1. 单一职责原则的重要性
    通过这次开发,我深刻体会到SRP的价值:

每个类只做一件事,使代码更易于理解和维护

修改一个功能时不会意外影响其他功能

测试时可以针对每个类单独测试

  1. 状态管理的艺术
    电梯系统本质上是一个状态机,我学到了:

明确的状态划分(上行、下行、空闲)

状态转换的条件要清晰明确

当前楼层和方向是核心状态,需要精心维护

  1. 请求队列的设计
    请求队列是系统的核心组件,我的体会是:

分离外部和内部队列更符合实际场景

队列操作要保证线程安全(虽然本题不涉及多线程)

合理的请求优先级策略对系统效率至关重要

三、代码质量提升经验

  1. 输入验证的必要性
    最初版本对输入验证不足,导致程序可能崩溃

改进后对所有输入进行严格验证:

楼层范围检查

请求格式检查

方向值检查

  1. 异常处理的完善
    从简单的忽略所有异常到有针对性的处理

对不同类型的错误采取不同策略:

无效楼层:忽略

格式错误:忽略

重复请求:过滤

  1. 日志输出的优化
    初期输出信息不够详细,难以调试

最终版本提供了清晰的运行日志:

电梯移动时的楼层和方向

开关门的明确指示

便于验证程序正确性

四、测试经验总结

  1. 测试用例设计
    边界测试:最小/最大楼层请求

特殊情况测试:连续相同请求

综合测试:混合内外请求

压力测试:大量请求连续输入

  1. 测试中发现的问题
    电梯在顶层和底层时的方向处理错误

某些情况下会错过合理请求

外部请求转内部请求的实现不完整

  1. 测试自动化的重要性
    初期手动测试效率低且容易遗漏

后期建立了简单的测试框架

考虑使用JUnit等单元测试框架会更好

改进建议

(对相应题目的编码改进给出自己的见解,做到可持续改进)
性能优化:

实现更高效的调度算法

考虑请求的时间因素(如高峰时段)

功能扩展:

支持多部电梯

增加超载检测

添加紧急停止功能

代码结构优化:

引入设计模式(如状态模式)

更好的抽象电梯行为

总结

(对本阶段三次题目集的综合性总结)
通过这个项目的多次迭代,我不仅提升了对面向对象设计的理解,也加深了对实际工程问题的认识。最大的收获是明白了良好的架构设计对软件质量的决定性影响。从最初将所有逻辑堆砌在一个类中,到最后清晰的四个类分工协作,代码的可读性、可维护性和可扩展性都得到了显著提升。

这个项目也让我认识到,软件开发是一个不断迭代和优化的过程,每次重构都能发现之前设计的不足,并找到更好的解决方案。这种持续改进的思维方式对成为一个优秀的软件工程师至关重要。

posted @ 2025-04-18 19:47  良穗  阅读(51)  评论(1)    收藏  举报