第一次blog作业
这三次的PTA作业,最难的都是电梯的题目,题目集5~7主要围绕单部电梯调度程序的设计与实现展开,通过三次连续出题逐步完善电梯系统的设计。题目集5是基础版本,但在最开始的时候并不熟悉java的使用,花费了大量时间去完成题目要求,拼尽全力去通过测试点。题目集6和7则分别进行了两次迭代设计,我在完成的过程中逐步引入更合理的类结构和更复杂的业务逻辑,不断修改代码,使得其更加完善。
1.知识点分布:
面向对象设计原则(特别是单一职责原则)定义:一个类应该只有一个发生变化的原因。如果一个类负责多项职责,当其中一项职责发生变化时,可能会导致其他职责受到影响。• 优点:• 降低类的复杂度:类的职责单一,其内部逻辑相对简单,易于理解和维护。• 提高类的可读性:单一职责的类更符合人类的思维方式,阅读代码时更容易把握其功能。• 增强系统的可维护性:当需求发生变化时,只需要修改与该职责相关的类,而不会影响到其他部分。• 降低变更风险:一个类只负责一项职责,当对该职责进行修改时,不会引入其他风险。
类的设计与封装确定类的职责:根据需求分析,明确类应该承担哪些功能,避免职责过多或过少。• 合理划分类的层次结构:通过继承和接口等方式,构建合理的类层次结构,提高代码的复用性和可扩展性。• 遵循设计原则:在设计类时,要遵循面向对象设计原则,如单一职责原则、开闭原则等,以确保类的设计具有良好的灵活性和可维护性。(二)封装• 定义:封装是面向对象编程的核心概念之一,它将对象的属性和行为封装在一起,隐藏对象的内部实现细节,只通过公共接口(方法)对外提供服务。• 实现方式:• 私有化成员变量:将类的成员变量设置为私有(private),防止外部直接访问和修改。• 提供公共方法:通过公共方法(getter和setter方法)来获取和设置成员变量的值,同时可以在这些方法中添加逻辑,对成员变量的访问和修改进行控制。• 优点:• 隐藏内部实现细节:外部代码不需要关心对象内部的具体实现,只需要通过接口与对象交互,降低了代码的耦合性。• 保护数据的安全性:通过封装可以限制对成员变量的访问,防止外部代码对数据进行非法操作。• 提高代码的可维护性:当需要修改对象的内部实现时,只要保持接口不变,外部代码不需要进行修改。
队列数据结构及其应用 :队列的定义队列是一种先进先出(FIFO)的线性数据结构,它允许在一端(队尾)插入元素,在另一端(队头)删除元素。队列的基本操作包括入队(enqueue)、出队(dequeue)、查看队头元素(peek)和判断队列是否为空等。(二)队列的实现方式• 数组实现:使用数组来存储队列中的元素,通过两个指针(队头指针和队尾指针)来记录队列的头和尾的位置。当队列满时,需要进行数组扩容或循环利用数组空间。• 链表实现:使用链表来存储队列中的元素,通过头节点和尾节点来操作队列。链表实现的队列在插入和删除操作时不需要移动元素,效率较高。(三)队列的应用• 任务调度:在操作系统中,任务调度器使用队列来管理进程的执行顺序,按照进程的优先级或到达时间将进程加入队列,然后按照队列的顺序调度进程执行。• 消息传递:在分布式系统中,队列可以用于消息传递,消息生产者将消息发送到队列中,消息消费者从队列中取出消息进行处理,实现生产者和消费者之间的解耦。• 缓冲区:在数据流处理中,队列可以作为缓冲区,暂时存储数据,等待后续处理。例如,在音频播放器中,音频数据先存储在队列中,然后由播放器从队列中取出数据进行播放。• 模拟真实场景:如银行排队系统,顾客按照到达顺序进入队列,依次办理业务。
状态模式在电梯系统中的应用:状态模式的定义状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变其行为,对象看起来好像修改了其类。状态模式通过将状态封装到独立的类中,将状态与行为解耦,使得状态的切换更加灵活和清晰。状态模式在电梯系统中的应用• 电梯的状态:电梯系统可以有多种状态,如“开门”状态、“关门”状态、“运行”状态、“停止”状态、“故障”状态等。• 状态类的设计:为每种状态创建一个状态类,这些状态类都实现一个共同的接口(如 ElevatorState 接口),接口中定义了电梯在该状态下可以执行的操作(如 openDoor() 、 closeDoor() 、 run() 等)。• 状态切换:电梯类持有一个状态对象的引用,当电梯的状态发生变化时,只需要将状态对象切换到对应的状态类实例即可。例如,当电梯从“停止”状态切换到“运行”状态时,电梯类将状态对象设置为 RunningState 类的实例。• 优点:• 将状态与行为解耦:状态模式将电梯的状态和行为分离,使得状态的切换更加灵活,也便于对状态进行扩展和维护。• 符合开闭原则:当需要增加新的状态时,只需要添加新的状态类,而不需要修改现有的代码。• 提高系统的可读性和可维护性:通过状态类的封装,电梯系统的状态逻辑更加清晰,便于理解和维护。
输入验证与异常处理:输入验证• 定义:输入验证是指在程序接收用户输入之前,对输入数据进行检查,确保输入数据的合法性、完整性和准确性。• 重要性:• 防止程序错误:非法的输入数据可能会导致程序运行出错,甚至崩溃。通过输入验证可以提前发现并处理这些问题,提高程序的健壮性。• 防止安全漏洞:恶意的输入可能会导致安全漏洞,如SQL注入、XSS攻击等。通过严格的输入验证可以有效防止这些安全威胁。• 实现方式:• 格式验证:检查输入数据是否符合预期的格式,如日期格式、电子邮件格式、电话号码格式等。可以使用正则表达式等工具进行格式验证。• 范围验证:检查输入数据是否在合理的范围内,如年龄是否在0到150之间,价格是否为正数等。• 类型验证:检查输入数据的类型是否正确,如是否为整数、字符串、浮点数等。• 内容验证:检查输入数据的内容是否符合业务规则,如用户名是否已存在,密码是否符合复杂度要求等。(二)异常处理• 定义:异常处理是指在程序运行过程中,当出现异常情况时,通过捕获和处理异常,使程序能够正常运行或优雅地终止。• Java异常处理机制:• 抛出异常(throw):当程序运行过程中出现异常情况时,通过 throw 关键字抛出一个异常对象,异常对象可以是系统预定义的异常类(如 NullPointerException 、 IOException 等),也可以是自定义的异常类。• 捕获异常(try-catch):通过 try-catch 块捕获异常, try 块中包含可能会抛出异常的代码, catch 块中定义了对异常的处理逻辑。当 try 块中的代码抛出异常时,程序会跳转到对应的 catch 块中执行。• finally块: finally 块用于定义一些必须执行的代码,无论是否捕获到异常, finally 块中的代码都会被执行。通常用于释放资源,如关闭文件流、数据库连接等。• 声明异常(throws):当一个方法可能会抛出异常时,可以通过 throws 关键字声明该方法可能会抛出的异常类型,将异常的处理责任抛给
2.题量与难度:
题目集5:5题,中等难度
题目集6:3题,较难(类设计迭代)
题目集7:3题,较难(再次迭代)
整体难度呈递增趋势,每次迭代都在前一次基础上增加了新的设计要求,体现了渐进式学习和改进的思路。
3.设计与分析
题目集5:单部电梯调度程序(基础版)
类设计
基础版本采用单一类设计,将所有功能集中在Elevator类中:
java
public class Elevator {
private int minFloor;
private int maxFloor;
private int currentFloor;
private String direction;
private String status;
private Queue
private Queue
private Queue
// 构造方法、getter/setter等
public void addRequest(String request) {...}
public void processRequests() {...}
private void move() {...}
private void openDoor(int floor) {...}
private void closeDoor() {...}
}
核心算法分析
电梯调度采用"LOOK"算法,优先处理同方向请求:
java
public void processRequests() {
while (!innerRequests.isEmpty() || !upRequests.isEmpty() || !downRequests.isEmpty()) {
if (direction.equals("UP")) {
// 处理上行请求
if (currentFloor < maxFloor &&
(innerRequests.contains(currentFloor) ||
upRequests.contains(currentFloor)) {
openDoor(currentFloor);
closeDoor();
}
// 移动逻辑
} else if (direction.equals("DOWN")) {
// 类似下行处理
}
// 方向切换逻辑
}
}
SourceMonitor报表
方法复杂度较高(processRequests()的复杂度达到15)
类行数超过100行,违背单一职责原则
注释覆盖率约30%
类图
图表
代码
classDiagram
class Elevator{
-minFloor: int
-maxFloor: int
-currentFloor: int
-direction: String
-status: String
-innerRequests: Queue
-upRequests: Queue
-downRequests: Queue
+addRequest(String): void
+processRequests(): void
-move(): void
-openDoor(int): void
-closeDoor(): void
}
题目集6:单部电梯调度程序(类设计迭代)
改进点
将单一类拆分为多个职责明确的类
增加输入验证和重复请求过滤
使用控制类专门处理调度逻辑
类结构
java
// 请求类
public class Request {
private int floor;
private String direction; // "UP", "DOWN" or null
// 构造方法、验证方法等
}
// 队列类
public class RequestQueue {
private Queue
private Queue
private Queue
// 添加、获取请求方法
}
// 电梯类
public class Elevator {
private int currentFloor;
private String direction;
private String status;
// 移动、开关门方法
}
// 控制类
public class ElevatorController {
private Elevator elevator;
private RequestQueue queue;
// 调度算法实现
}
调度算法改进
java
public void schedule() {
while (!queue.isEmpty()) {
Request next = getNextRequest();
moveTo(next.getFloor());
processFloor();
}
}
private Request getNextRequest() {
// 优先同方向请求
if (elevator.getDirection().equals("UP")) {
return queue.getUpQueue().peek();
} else {
return queue.getDownQueue().peek();
}
}
SourceMonitor改进
平均方法复杂度从15降至8
类平均行数控制在50行左右
注释覆盖率提升至50%
类图
图表
代码
classDiagram
class Request{
-floor: int
-direction: String
+isValid(int min, int max): boolean
}
class RequestQueue{
-innerQueue: Queue<Request>
-upQueue: Queue<Request>
-downQueue: Queue<Request>
+addRequest(Request): boolean
}
class Elevator{
-currentFloor: int
-direction: String
-status: String
+moveTo(int): void
}
class ElevatorController{
-elevator: Elevator
-queue: RequestQueue
+schedule(): void
}
RequestQueue --> Request
ElevatorController --> Elevator
ElevatorController --> RequestQueue
题目集7:单部电梯调度程序(加入乘客类)
主要变更
引入Passenger类替代Request类
外部请求格式变为<源楼层,目的楼层>
处理外部请求后自动添加内部请求
新增Passenger类
java
public class Passenger {
private int sourceFloor;
private int destinationFloor;
public boolean isValid(int minFloor, int maxFloor) {
return sourceFloor >= minFloor && sourceFloor <= maxFloor &&
destinationFloor >= minFloor && destinationFloor <= maxFloor &&
sourceFloor != destinationFloor;
}
}
调度逻辑调整
java
public void processExternalRequest(Passenger p) {
if (p.getSourceFloor() == currentFloor) {
openDoor();
innerQueue.add(p.getDestinationFloor()); // 自动添加内部请求
closeDoor();
} else {
moveTo(p.getSourceFloor());
}
}
复杂度分析
方法平均复杂度维持在8左右
类数量增加但每个类职责更单一
注释覆盖率保持50%以上
4.采坑心得
题目集5实现中的问题
无效楼层处理不足:
初始版本仅简单检查楼层是否在范围内,未考虑其他无效情况:
java
// 错误示例
if (floor > maxFloor || floor < minFloor) {
return;
}
测试用例<22,DOWN>和<30>未被正确处理
方向切换逻辑缺陷:
当同方向请求处理完后,没有正确判断反向请求:
java
// 错误逻辑
if (upRequests.isEmpty()) {
direction = "DOWN";
}
应改为检查所有可能请求:
java
if (!hasRequestsInCurrentDirection()) {
direction = reverseDirection();
}
状态管理混乱:
电梯状态(停止、移动、开门)转换不清晰,导致输出不符合预期:
java
// 错误的状态转换
status = "OPEN";
System.out.println("Open Door...");
status = "CLOSE"; // 缺少等待时间
题目集6改进中的发现
重复请求过滤实现:
最初使用简单的等值比较:
java
if (newRequest.equals(lastRequest)) {
return false;
}
后发现需要深度比较请求内容,改进为:
java
public boolean isDuplicate(Request newReq) {
return queue.stream().anyMatch(r ->
r.getFloor() == newReq.getFloor() &&
Objects.equals(r.getDirection(), newReq.getDirection()));
}
类职责划分争议:
最初将输入验证放在ElevatorController中,后发现应属于Request类的职责:
java
// 改进前
controller.validate(request);
// 改进后
if (request.isValid(min, max)) {
controller.addRequest(request);
}
题目集7的挑战
请求格式变更带来的影响:
外部请求从<楼层,方向>变为<源,目的>,导致调度算法需要调整:
java
// 旧逻辑
if (request.getDirection().equals("UP")) {
upQueue.add(request);
}
// 新逻辑
if (request.getSourceFloor() < request.getDestinationFloor()) {
upQueue.add(request);
}
自动添加内部请求的时机:
最初在处理外部请求后立即添加内部请求,导致顺序问题:
java
// 错误实现
processExternal(p);
innerQueue.add(p.getDestination()); // 可能插队
// 正确实现
innerQueue.add(p.getDestination()); // 添加到队尾
改进
代码结构改进
引入状态模式:
当前使用字符串表示电梯状态,可改进为状态模式:
java
interface ElevatorState {
void openDoor();
void closeDoor();
void move();
}
class StoppedState implements ElevatorState {...}
class MovingState implements ElevatorState {...}
使用策略模式实现调度算法:
便于未来扩展不同调度策略:
java
interface SchedulingStrategy {
Request getNextRequest(RequestQueue queue, Elevator elevator);
}
class LookStrategy implements SchedulingStrategy {...}
class ScanStrategy implements SchedulingStrategy {...}
功能增强
增加电梯容量限制:
java
public class Elevator {
private int capacity;
private int currentLoad;
public boolean isFull() {
return currentLoad >= capacity;
}
}
添加紧急停止功能:
java
public void emergencyStop() {
status = "EMERGENCY";
openDoor(currentFloor);
// 清空队列等
}
测试覆盖完善
边界条件测试:
最小/最大楼层请求
连续相同请求
反向请求插队情况
性能测试:
java
@Test
void testLargeNumberOfRequests() {
for (int i = 0; i < 1000; i++) {
controller.addRequest(new Request(...));
}
assertTimeout(Duration.ofSeconds(1), () -> {
controller.schedule();
});
}
5.总结
学习收获
通过这三次题目集的实践,我获得了以下收获:面向对象设计能力提升:深刻理解了单一职责原则的实际应用学会了如何合理划分类职责掌握了类图设计工具的使用算法设计能力增强:实现了电梯调度LOOK算法;学习了状态管理和方向决策逻辑;掌握了队列数据结构的应用场景;工程实践能力进步:学会了使用SourceMonitor分析代码质量 掌握了基于PowerDesigner的类图设计提高了调试和问题定位能力
待改进领域
设计模式掌握不足:对状态模式、策略模式等应用还不够熟练;需要更多实践来理解模式的应用场景;测试驱动开发:;当前主要是先编码后测试;需要学习如何先写测试再开发;性能优化意识:;当前主要关注功能实现;需要更多考虑算法效率和资源消耗
个人学习计划
基于这三次题目集的经验,我制定了以下学习计划:
重点研究状态模式、策略模式在实际系统中的应用
通过阅读开源项目源码(如Apache Commons等)学习优秀设计
每月完成一个应用设计模式的小项目
代码质量提升:
在日常编码中坚持使用代码质量分析工具
学习单元测试框架(如JUnit),实践测试驱动开发
参与代码审查,学习他人的代码优点
算法能力加强:
系统学习调度算法,不仅限于电梯调度
参加算法竞赛,提升算法思维和编码能力
研究分布式系统中的调度问题
项目经验延伸
这三次题目集的成果可以进一步延伸为更有价值的项目:
电梯仿真系统:
基于现有代码开发可视化电梯仿真界面
加入多部电梯调度,实现更复杂的调度算法
增加数据统计功能,如平均等待时间计算等
智能调度系统:
引入机器学习算法,根据历史数据预测电梯使用高峰
实现动态调度策略,提高电梯运行效率
加入节能模式,在低峰期优化电力消耗
通过这三次迭代开发,我对软件工程的核心思想有了更深体会:
迭代开发的价值:
从简单到复杂的渐进式开发降低了认知负担
每次迭代都有明确目标,避免过度设计
便于早期发现问题,降低修改成本
设计原则的重要性:
单一职责原则使代码更易维护和扩展
良好的封装减少了模块间的耦合
清晰的接口定义提高了代码可读性
文档的必要性:
类图等设计文档帮助理清思路
好的注释和文档节省后期维护成本
版本变更记录有助于追踪问题
对职业发展的启示
这些实践经历对我的职业规划也产生了积极影响:
认识到架构设计能力的重要性:
好的架构能显著降低后续开发难度
设计缺陷往往导致后期大量返工
需要培养系统思维和抽象能力
重视代码质量:
职业项目中代码会被多人长期维护
质量差的代码会增加企业成本
养成良好的编码习惯至关重要
终身学习的必要性:
技术不断更新,需要持续学习
设计模式和原则是持久的知识
解决问题的能力比具体技术更重要
结语
这三次题目集的实践让我受益匪浅,不仅提升了我的编程能力和设计思维,也让我对软件开发的工程性有了更深刻的认识。从最初将所有逻辑塞进一个类,到后来合理划分职责、应用设计原则,这个过程让我真切体会到了良好设计带来的好处。
在未来的学习中,我将继续巩固面向对象设计能力,深入学习设计模式,并尝试将这些知识应用到更复杂的项目中。同时,我也会更加重视代码质量和工程实践,培养良好的开发习惯。
感谢老师精心设计的这组渐进式题目,这种从简单到复杂、不断迭代改进的教学方式非常有助于我们掌握软件设计的精髓。建议可以继续保持这种教学模式,并适当增加一些真实案例的分析和讨论,帮助我们更好地将理论知识转化为实践能力。
最后,我会将这三次题目集的收获应用到后续的学习和项目中,不断提高自己的软件开发能力,为未来的职业发展打下坚实基础。相信通过持续的学习和实践,我能够成为一名优秀的软件工程师。

浙公网安备 33010602011771号