BLOG1 电梯题目567总结
- 一·前言
在之前的学习中,对于java和C语言之间的区别感到不是很大,所以第一次进行作业集时仍然采用C语言面向过程来设计,没有进行面向对象的设计。在后来的不断学习中,才了解到java的真正的流程,同时对作业进行更变。
三次电梯作业不断进行优化,从开始的一个类到符合java流程再到更符合实际,每次优化都让我有新的收获:学会了怎么设计更合理的类结构(MVC)、怎么把功能模块化(单一职责原则)、怎么处理复杂的业务逻辑。现在回头看,这几道题教会我的不只是单纯的写代码,更重要的是如何分析问题、拆分需求、设计方案、逐步优化。 - 二·设计与分析
1.第一次题目集
具体要求
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
实际代码
点击查看代码
import java.util.*;
class Elevator {
private int minFloor;
private int maxFloor;
private int currentFloor;
private String direction;
private String status;
private List<Integer> innerQueue;
private List<Request> outQueue;
private static class Request {
int floor;
String direction;
Request(int floor, String direction) {
this.floor = floor;
this.direction = direction;
}
}
public Elevator(int minFloor, int maxFloor) {
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.currentFloor = minFloor;
this.direction = "IDLE";
this.status = "Stopped";
this.innerQueue = new ArrayList<>();
this.outQueue = new ArrayList<>();
}
public void addInnerRequest(int floor) {
if (!testFloor(floor)) {
System.out.println("Wrong Format!");
return;
}
innerQueue.add(floor);
}
public void addOutRequest(int floor, String direction) {
if (!testFloor(floor)) {
System.out.println("Wrong Format!");
return;
}
outQueue.add(new Request(floor, direction));
}
private boolean testFloor(int floor) {
return (floor >= this.minFloor && floor <= this.maxFloor);
}
public List<Integer> getInnerRequests() {
return innerQueue;
}
public List<Request> getOutRequests() {
return outQueue;
}
public void processRequests() {
while (!innerQueue.isEmpty() || !outQueue.isEmpty()) {
determineDirection();
move();
shouldStop();
}
}
private void determineDirection() {
if (direction.equals("IDLE")) {
if (!innerQueue.isEmpty() || !outQueue.isEmpty()) {
direction = "UP";
}
}
if (!innerQueue.isEmpty() && !outQueue.isEmpty()) {
if (direction.equals("UP")){
direction = (innerQueue.get(0) > currentFloor || outQueue.get(0).floor > currentFloor) ? "UP" : "DOWN";
}
else if (direction.equals("DOWN")){
direction = (innerQueue.get(0) < currentFloor || outQueue.get(0).floor < currentFloor) ? "DOWN" : "UP";
}
}
else if (innerQueue.isEmpty() && !outQueue.isEmpty()) {
direction = (outQueue.get(0).floor < currentFloor) ? "DOWN" : "UP";
}
else if (!innerQueue.isEmpty() && outQueue.isEmpty()) {
direction = (innerQueue.get(0) < currentFloor) ? "DOWN" : "UP";
}
}
private void move() {
if (currentFloor==1){
System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
}
if (direction.equals("UP")) {
currentFloor++;
} else if (direction.equals("DOWN")) {
currentFloor--;
}
System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
}
private void shouldStop() {
String r = this.status;
if (!innerQueue.isEmpty() && !outQueue.isEmpty()) {
r = "Moving";
if (direction.equals("UP")
&¤tFloor<=innerQueue.get(0)
&¤tFloor<=outQueue.get(0).floor
&&innerQueue.get(0)>=outQueue.get(0).floor
&&outQueue.get(0).direction.equals("DOWN")) {
if (innerQueue.get(0) == currentFloor) {
if(innerQueue.get(0) == outQueue.get(0).floor&&outQueue.get(0).direction.equals("UP")){
outQueue.remove(0);
}
innerQueue.remove(0);
r = "Stopped";
}
}
else if (direction.equals("DOWN")
&¤tFloor>=innerQueue.get(0)
&¤tFloor>=outQueue.get(0).floor
&&innerQueue.get(0)<=outQueue.get(0).floor
&&outQueue.get(0).direction.equals("UP")) {
if (innerQueue.get(0) == currentFloor) {
if(innerQueue.get(0) == outQueue.get(0).floor&&outQueue.get(0).direction.equals("DOWN")){
outQueue.remove(0);
}
innerQueue.remove(0);
r = "Stopped";
}
}
else {
if (innerQueue.get(0) == currentFloor&&innerQueue.get(0) != outQueue.get(0).floor) {
innerQueue.remove(0);
r = "Stopped";
}
else if (outQueue.get(0).floor == currentFloor&&innerQueue.get(0) != outQueue.get(0).floor) {
outQueue.remove(0);
r = "Stopped";
}
else if(innerQueue.get(0) == currentFloor
&&innerQueue.get(0) == outQueue.get(0).floor
&&outQueue.get(0).direction.equals(direction)){
outQueue.remove(0);
innerQueue.remove(0);
r = "Stopped";
}
}
}
else if (innerQueue.isEmpty() && !outQueue.isEmpty()) {
r = "Moving";
if (outQueue.get(0).floor == currentFloor) {
outQueue.remove(0);
r = "Stopped";
}
}
else if (!innerQueue.isEmpty() && outQueue.isEmpty()) {
r = "Moving";
if (innerQueue.get(0) == currentFloor) {
innerQueue.remove(0);
r = "Stopped";
}
}
if (r.equals("Stopped")) {
openDoor();
closeDoor();
}
}
// 开门
private void openDoor() {
System.out.println("Open Door # Floor " + currentFloor);
}
// 关门
private void closeDoor() {
System.out.println("Close Door");
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String data; //输入数据:字符串
int floor = 0;
String direction = null;
int minFloor,maxFloor; //电梯最低楼层、最高楼层
String request = ""; //提取出的乘客请求字符串
ArrayList<String> list = new ArrayList<>(); //用于接收用户输入的数组
data = input.next();
while(!data.equalsIgnoreCase("End")){ //输入以“end”结束
list.add(data);
data = input.next();
}
minFloor = Integer.parseInt(list.get(0));//第一行,电梯最低楼层
maxFloor = Integer.parseInt(list.get(1));//第二行,电梯最高楼层
Elevator elevator = new Elevator(minFloor, maxFloor);//创建电梯对象
for(int i = 2; i < list.size(); i++){//从第三行开始为乘客请求
request = list.get(i);
if(request.contains(",")){//外部请求
if (!request.matches("<\\d+,\\s*(UP|DOWN)>")) {
System.out.println("Wrong Format");
}
String[] parts = request.replaceAll("[<>]", "").split(",");
floor = Integer.parseInt(parts[0].trim());
direction = parts[1].trim().toUpperCase();
elevator.addOutRequest(floor, direction);//外部请求入队,格式为<楼层数,方向>
}else{
if (!request.matches("<\\d+>")) {//内部请求
System.out.println("Wrong Format");
}
floor = Integer.parseInt(request.replaceAll("[<>]", ""));
elevator.addInnerRequest(floor);//内部请求入队,格式为<楼层数>
}
}
while(!elevator.getInnerRequests().isEmpty()|| !elevator.getOutRequests().isEmpty()){
elevator.processRequests(); //一次性处理所有的内、外部乘客请求
}
input.close();
}
}
类图

分析
点击查看
类和属性
Elevator类
属性:
minFloor:电梯的最低楼层。
maxFloor:电梯的最高楼层。
currentFloor:电梯当前所在的楼层。
direction:电梯的运行方向(如"UP"或"DOWN")。
status:电梯的当前状态(如"MOVING"或"STOPPED")。
innerQueue:内部请求队列,存储电梯内部乘客的楼层请求。
outQueue:外部请求队列,存储电梯外部乘客的请求。
方法:
构造函数:初始化电梯对象,设置最低楼层和最高楼层。
addInnerRequest(int floor):添加内部请求。
addOutRequest(int floor, String direction)`:添加外部请求。
testFloor(int floor):检查楼层是否有效。
getInnerRequests():获取内部请求队列。
getOutRequests():获取外部请求队列。
processRequests():处理所有请求。
determineDirection():确定电梯的运行方向。
move():移动电梯。
shouldStop():判断电梯是否应该停止。
openDoor():打开电梯门。
closeDoor():关闭电梯门。
Request类
属性:
floor:请求的楼层。
direction:请求的方向。
方法:
构造函数:初始化请求对象,设置楼层和方向。
`Main`类
方法:
main(String[] args)`:程序的入口点,负责启动电梯系统。
报表

分析
点击查看
行数 (Lines):250 行代码。
语句数 (Statements):137 个语句。
分支语句百分比 (Percent Branch Statements):24.8%,表示代码中条件分支语句的比例。
方法调用语句数 (Method Call Statements):106 个方法调用。
带注释的行百分比 (Percent Lines with Comments):5.2%,代码注释的比例较低。
类和接口数 (Classes and Interfaces):3 个类或接口。
每个类的方法数 (Methods per Class):平均每个类有 4.33 个方法。
每个方法的平均语句数 (Average Statements per Method):8.54 个语句。
最复杂方法的行数 (Line Number of Most Complex Method):109 行,Elevator.shouldStop()方法。
最复杂方法的名称 (Name of Most Complex Method):Elevator.shouldStop() 。
最大复杂度 (Maximum Complexity):34,表示方法的圈复杂度。
最深代码块的行数 (Line Number of Deepest Block):122 行。
最大代码块深度 (Maximum Block Depth):6 层。
平均代码块深度 (Average Block Depth):2.69 层。
平均复杂度 (Average Complexity):6.17。
2.第二次题目集
具体要求
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类。
电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
实际代码
点击查看代码
import java.util.*;
enum Direction {
UP, DOWN, IDLE
}
enum State {
MOVING, STOPPED
}
class Elevator {
private int currentFloor;
private Direction direction;
private State state;
private final int maxFloor;
private final int minFloor;
public Elevator(int minFloor, int maxFloor) {
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.currentFloor = minFloor;
this.direction = Direction.IDLE;
this.state = State.STOPPED;
}
public int getCurrentFloor() {
return currentFloor;
}
public void setCurrentFloor(int currentFloor) {
this.currentFloor = currentFloor;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getMaxFloor() {
return maxFloor;
}
public int getMinFloor() {
return minFloor;
}
public boolean isValidFloor(int floor) {
return floor >= minFloor && floor <= maxFloor;
}
}
class ExternalRequest {
private final int floor;
private final Direction direction;
public ExternalRequest(int floor, Direction direction) {
this.floor = floor;
this.direction = direction;
}
public int getFloor() {
return floor;
}
public Direction getDirection() {
return direction;
}
}
class RequestQueue {
private LinkedList<Integer> internalRequests = new LinkedList<>();
private LinkedList<ExternalRequest> externalRequests = new LinkedList<>();
public LinkedList<Integer> getInternalRequests() {
return internalRequests;
}
public LinkedList<ExternalRequest> getExternalRequests() {
return externalRequests;
}
public void addInternalRequest(int floor) {
if (internalRequests.isEmpty() || internalRequests.getLast()!=floor) {
internalRequests.add(floor);
}
}
public void addExternalRequest(int floor, Direction direction) {
ExternalRequest newRequest = new ExternalRequest(floor, direction);
if ( externalRequests.isEmpty()
|| externalRequests.getLast().getFloor()!=floor
|| externalRequests.getLast().getDirection()!=direction) {
externalRequests.add(newRequest);
}
}
}
class Controller {
private Elevator elevator;
private RequestQueue queue;
public Controller(Elevator elevator, RequestQueue queue) {
this.elevator = elevator;
this.queue = queue;
}
public void processRequests() {
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<ExternalRequest> outQueue = queue.getExternalRequests();
while (!innerQueue.isEmpty() || !outQueue.isEmpty()) {
determineDirection();
shouldStop();
if(innerQueue.isEmpty() && outQueue.isEmpty()){
break;
}
move();
shouldStop();
}
}
private void determineDirection() {
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<ExternalRequest> outQueue = queue.getExternalRequests();
int currentFloor = elevator.getCurrentFloor();
Direction direction = elevator.getDirection();
if (direction==Direction.IDLE) {
if (!innerQueue.isEmpty() || !outQueue.isEmpty()) {
direction = Direction.UP;
System.out.println("Current Floor: "+currentFloor+" Direction: UP");
}
}
if (!innerQueue.isEmpty() && !outQueue.isEmpty()) {
if (direction==Direction.UP){
direction = (innerQueue.get(0) > currentFloor || outQueue.get(0).getFloor() > currentFloor) ? Direction.UP : Direction.DOWN;
}
else if (direction==Direction.DOWN){
direction = (innerQueue.get(0) < currentFloor || outQueue.get(0).getFloor() < currentFloor) ? Direction.DOWN : Direction.UP;
}
}
else if (innerQueue.isEmpty() && !outQueue.isEmpty()) {
direction = (outQueue.get(0).getFloor() < currentFloor) ? Direction.DOWN : Direction.UP;
}
else if (!innerQueue.isEmpty() && outQueue.isEmpty()) {
direction = (innerQueue.get(0) < currentFloor) ? Direction.DOWN : Direction.UP;
}
elevator.setDirection(direction);
}
private void move() {
int currentFloor = elevator.getCurrentFloor();
Direction direction = elevator.getDirection();
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<ExternalRequest> outQueue = queue.getExternalRequests();
currentFloor=getNextFloor();
System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
elevator.setCurrentFloor(currentFloor);
}
private void shouldStop() {
State r = State.MOVING;
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<ExternalRequest> outQueue = queue.getExternalRequests();
int currentFloor = elevator.getCurrentFloor();
Direction direction = elevator.getDirection();
if (!innerQueue.isEmpty() && !outQueue.isEmpty()) {
r = State.MOVING;
if (direction==Direction.UP
&¤tFloor<=innerQueue.get(0)
&¤tFloor<=outQueue.get(0).getFloor()
&&innerQueue.get(0)>=outQueue.get(0).getFloor()
&&outQueue.get(0).getDirection()==Direction.DOWN) {
if (innerQueue.get(0) == currentFloor) {
if(innerQueue.get(0) == outQueue.get(0).getFloor()
&&outQueue.get(0).getDirection()==Direction.UP){
outQueue.remove(0);
}
innerQueue.remove(0);
r = State.STOPPED;
}
}
else if (direction==Direction.DOWN
&¤tFloor>=innerQueue.get(0)
&¤tFloor>=outQueue.get(0).getFloor()
&&innerQueue.get(0)<=outQueue.get(0).getFloor()
&&outQueue.get(0).getDirection()==Direction.UP) {
if (innerQueue.get(0) == currentFloor) {
if(innerQueue.get(0) == outQueue.get(0).getFloor()
&&outQueue.get(0).getDirection()==Direction.DOWN){
outQueue.remove(0);
}
innerQueue.remove(0);
r =State.STOPPED;
}
}
else {
if (innerQueue.get(0) == currentFloor&&innerQueue.get(0) != outQueue.get(0).getFloor()) {
innerQueue.remove(0);
r = State.STOPPED;
}
else if (outQueue.get(0).getFloor() == currentFloor
&&innerQueue.get(0) != outQueue.get(0).getFloor()
&&outQueue.get(0).getDirection() ==direction) {
outQueue.remove(0);
r = State.STOPPED;
}
else if(innerQueue.get(0) == currentFloor
&&innerQueue.get(0) == outQueue.get(0).getFloor()
&&outQueue.get(0).getDirection() ==direction){
outQueue.remove(0);
innerQueue.remove(0);
r = State.STOPPED;
}
}
}
else if (innerQueue.isEmpty() && !outQueue.isEmpty()) {
r = State.MOVING;
if (outQueue.get(0).getFloor() == currentFloor) {
outQueue.remove(0);
r = State.STOPPED;
}
}
else if (!innerQueue.isEmpty() && outQueue.isEmpty()) {
r = State.MOVING;
if (innerQueue.get(0) == currentFloor) {
innerQueue.remove(0);
r = State.STOPPED;
}
}
if (r==State.STOPPED) {
openDoors();
}
}
public int getNextFloor() {
int currentFloor = elevator.getCurrentFloor();
if (elevator.getDirection() == Direction.UP) {
return currentFloor + 1;
} else if (elevator.getDirection() == Direction.DOWN) {
return currentFloor - 1;
}
return currentFloor;
}
public void openDoors() {
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<ExternalRequest> outQueue = queue.getExternalRequests();
System.out.println("Open Door # Floor " + elevator.getCurrentFloor());
System.out.print("Close Door");
if(!innerQueue.isEmpty()||!outQueue.isEmpty()){
System.out.printf("\n");
}
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String data; //输入数据:字符串
int floor = 0;
Direction direction = null;
int minFloor,maxFloor; //电梯最低楼层、最高楼层
String request = ""; //提取出的乘客请求字符串
ArrayList<String> list = new ArrayList<>(); //用于接收用户输入的数组
data = input.next();
while(!data.equalsIgnoreCase("End")){ //输入以“end”结束
list.add(data);
data = input.next();
}
minFloor = Integer.parseInt(list.get(0));//第一行,电梯最低楼层
maxFloor = Integer.parseInt(list.get(1));//第二行,电梯最高楼层
Elevator elevator = new Elevator(minFloor, maxFloor);//创建电梯对象
RequestQueue queue = new RequestQueue();
Controller controller = new Controller(elevator, queue);
for(int i = 2; i < list.size(); i++){//从第三行开始为乘客请求
request = list.get(i);
if(request.contains(",")){//外部请求
if (!request.matches("<\\d+,\\s*(UP|DOWN)>")) {
System.out.println("Wrong Format");
}
String[] parts = request.replaceAll("[<>]", "").split(",");
floor = Integer.parseInt(parts[0].trim());
direction = Direction.valueOf(parts[1].trim().toUpperCase());
if(elevator.isValidFloor(floor)){
queue.addExternalRequest(floor, direction);//外部请求入队,格式为<楼层数,方向>
}
}else{
if (!request.matches("<\\d+>")) {//内部请求
System.out.println("Wrong Format");
}
floor = Integer.parseInt(request.replaceAll("[<>]", ""));
if(elevator.isValidFloor(floor)){
queue.addInternalRequest(floor);//内部请求入队,格式为<楼层数>
}
}
}
while (!queue.getInternalRequests().isEmpty() || !queue.getExternalRequests().isEmpty()) {
controller.processRequests(); //一次性处理所有的内、外部乘客请求
}
input.close();
}
}
类图

分析
点击查看
类
Elevator类
属性:
currentFloor:当前楼层。
direction:电梯运行方向,可能是UP、DOWN或IDLE。
state:电梯状态,可能是MOVING或STOPPING。
maxFloor和minFloor:电梯可运行的最大和最小楼层。
方法:
构造函数:初始化电梯。
getCurrentFloor()、setCurrentFloor()、getDirection()、setDirection()、getState()、setState():获取和设置电梯的当前状态。
getMaxFloor()、getMinFloor():获取电梯的最大和最小楼层。
isValidFloor():检查给定楼层是否有效。
Direction枚举
定义了电梯可能的运行方向:UP、DOWN和IDLE。
State枚举
定义了电梯的状态:MOVING和STOPPING。
ExternalRequest类
属性:
floor:请求的楼层。
direction:请求的方向。
方法:
构造函数:初始化外部请求。
getFloor()、getDirection():获取请求的楼层和方向。
RequestQueue类
属性:
internalRequests和externalRequests:内部和外部请求的队列。
方法:
getInternalRequests()、getExternalRequests():获取内部和外部请求。
addInternalRequest()、addExternalRequest():添加内部和外部请求。
Controller`类
属性:
elevator:电梯实例。
queue:请求队列。
方法:
构造函数:初始化控制器。
processRequests()、determineDirection()、move()、shouldStop()、getNextFloor()、openDoors():处理请求、确定方向、移动电梯、判断是否停止、获取下一个楼层和打开门。
Main类
方法:
main():程序的入口点。
报表

分析
点击查看
行数(Lines):346 行代码。
语句数(Statements):189 个语句。
分支语句百分比(Percent Branch Statements):20.6%,表示代码中条件分支语句的比例。
方法调用语句数(Method Call Statements):147 个方法调用。
带注释的行百分比(Percent Lines with Comments):3.2%,代码注释的比例较低。
类和接口数(Classes and Interfaces):7 个类或接口。
每个类的方法数(Methods per Class):平均每个类有 3.57 个方法。
每个方法的平均语句数(Average Statements per Method):5.76 个语句。
最复杂方法的行数(Line Number of Most Complex Method):178 行,`Controller.shouldStop()`方法。
最复杂方法的名称(Name of Most Complex Method):`Controller.shouldStop()`。
最大复杂度(Maximum Complexity):35,表示方法的圈复杂度。
最深代码块的行数(Line Number of Deepest Block):197 行。
最大代码块深度(Maximum Block Depth):6 层。
平均代码块深度(Average Block Depth):2.41 层。
平均复杂度(Average Complexity):3.92。
3.第三次题目集
具体要求
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
实际代码
点击查看代码
import java.util.*;
enum Direction {
UP, DOWN, IDLE
}
enum State {
MOVING, STOPPED
}
class Elevator {
private int currentFloor;
private Direction direction;
private State state;
private final int maxFloor;
private final int minFloor;
public Elevator(int minFloor, int maxFloor) {
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.currentFloor = minFloor;
this.direction = Direction.IDLE;
this.state = State.STOPPED;
}
public int getCurrentFloor() {
return currentFloor;
}
public void setCurrentFloor(int currentFloor) {
this.currentFloor = currentFloor;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getMaxFloor() {
return maxFloor;
}
public int getMinFloor() {
return minFloor;
}
public boolean isValidFloor(int floor) {
return floor >= minFloor && floor <= maxFloor;
}
}
class Passenger {
private int sourceFloor;
private int destinationFloor;
public Passenger(int sourceFloor,int destinationFloor) {
this.sourceFloor = sourceFloor;
this.destinationFloor = destinationFloor;
}
public int getsourceFloor() {
return sourceFloor;
}
public void setsourceFloor(int sourceFloor){
this.sourceFloor=sourceFloor;
}
public int getdestinationFloor() {
return destinationFloor;
}
public void setdestinationFloor(int destinationFloor){
this.destinationFloor=destinationFloor;
}
public Direction getDirection() {
return (sourceFloor>destinationFloor?Direction.DOWN:Direction.UP);
}
}
class RequestQueue {
private LinkedList<Integer> internalRequests = new LinkedList<>();
private LinkedList<Passenger> externalRequests = new LinkedList<>();
public LinkedList<Integer> getInternalRequests() {
return internalRequests;
}
public LinkedList<Passenger> getExternalRequests() {
return externalRequests;
}
public void addInternalRequest(int floor) {
if (internalRequests.isEmpty() || internalRequests.getLast()!=floor) {
internalRequests.add(floor);
}
}
public void addExternalRequest(int sourceFloor, int destinationFloor) {
Passenger passenger = new Passenger(sourceFloor,destinationFloor);
if ( externalRequests.isEmpty()
|| externalRequests.getLast().getsourceFloor()!=sourceFloor
|| externalRequests.getLast().getdestinationFloor()!=destinationFloor) {
externalRequests.add(passenger);
}
}
}
class Controller {
private Elevator elevator;
private RequestQueue queue;
public Controller(Elevator elevator, RequestQueue queue) {
this.elevator = elevator;
this.queue = queue;
}
public void processRequests() {
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<Passenger> outQueue = queue.getExternalRequests();
while (!innerQueue.isEmpty() || !outQueue.isEmpty()) {
determineDirection();
shouldStop();
if(innerQueue.isEmpty() && outQueue.isEmpty()){
break;
}
move();
shouldStop();
}
}
private void determineDirection() {
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<Passenger> outQueue = queue.getExternalRequests();
int currentFloor = elevator.getCurrentFloor();
Direction direction = elevator.getDirection();
if (direction==Direction.IDLE) {
if (!innerQueue.isEmpty() || !outQueue.isEmpty()) {
direction = Direction.UP;
System.out.println("Current Floor: "+currentFloor+" Direction: UP");
}
}
if (!innerQueue.isEmpty() && !outQueue.isEmpty()) {
if (direction==Direction.UP){
direction = (innerQueue.get(0) > currentFloor || outQueue.get(0).getsourceFloor() > currentFloor) ? Direction.UP : Direction.DOWN;
}
else if (direction==Direction.DOWN){
direction = (innerQueue.get(0) < currentFloor || outQueue.get(0).getsourceFloor() < currentFloor) ? Direction.DOWN : Direction.UP;
}
}
else if (innerQueue.isEmpty() && !outQueue.isEmpty()) {
direction = (outQueue.get(0).getsourceFloor() < currentFloor) ? Direction.DOWN : Direction.UP;
}
else if (!innerQueue.isEmpty() && outQueue.isEmpty()) {
direction = (innerQueue.get(0) < currentFloor) ? Direction.DOWN : Direction.UP;
}
elevator.setDirection(direction);
}
private void move() {
int currentFloor = elevator.getCurrentFloor();
Direction direction = elevator.getDirection();
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<Passenger> outQueue = queue.getExternalRequests();
currentFloor=getNextFloor();
System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
elevator.setCurrentFloor(currentFloor);
}
private void shouldStop() {
State r = State.MOVING;
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<Passenger> outQueue = queue.getExternalRequests();
int currentFloor = elevator.getCurrentFloor();
Direction direction = elevator.getDirection();
if (!innerQueue.isEmpty() && !outQueue.isEmpty()) {
r = State.MOVING;
if (direction==Direction.UP
&¤tFloor<=innerQueue.get(0)
&¤tFloor<=outQueue.get(0).getsourceFloor()
&&innerQueue.get(0)>=outQueue.get(0).getsourceFloor()
&&outQueue.get(0).getDirection()==Direction.DOWN) {
if (innerQueue.get(0) == currentFloor) {
if(innerQueue.get(0) == outQueue.get(0).getsourceFloor()
&&outQueue.get(0).getDirection()==Direction.UP){
queue.addInternalRequest(outQueue.get(0).getdestinationFloor());
outQueue.remove(0);
}
innerQueue.remove(0);
r = State.STOPPED;
}
}
else if (direction==Direction.DOWN
&¤tFloor>=innerQueue.get(0)
&¤tFloor>=outQueue.get(0).getsourceFloor()
&&innerQueue.get(0)<=outQueue.get(0).getsourceFloor()
&&outQueue.get(0).getDirection()==Direction.UP) {
if (innerQueue.get(0) == currentFloor) {
if(innerQueue.get(0) == outQueue.get(0).getsourceFloor()
&&outQueue.get(0).getDirection()==Direction.DOWN){
queue.addInternalRequest(outQueue.get(0).getdestinationFloor());
outQueue.remove(0);
}
innerQueue.remove(0);
r =State.STOPPED;
}
}
else {
if (innerQueue.get(0) == currentFloor&&innerQueue.get(0) != outQueue.get(0).getsourceFloor()) {
innerQueue.remove(0);
r = State.STOPPED;
}
else if (outQueue.get(0).getsourceFloor() == currentFloor
&&innerQueue.get(0) != outQueue.get(0).getsourceFloor()
&&outQueue.get(0).getDirection() ==direction) {
queue.addInternalRequest(outQueue.get(0).getdestinationFloor());
outQueue.remove(0);
r = State.STOPPED;
}
else if(innerQueue.get(0) == currentFloor
&&innerQueue.get(0) == outQueue.get(0).getsourceFloor()
&&outQueue.get(0).getDirection() ==direction){
queue.addInternalRequest(outQueue.get(0).getdestinationFloor());
outQueue.remove(0);
innerQueue.remove(0);
r = State.STOPPED;
}
}
}
else if (innerQueue.isEmpty() && !outQueue.isEmpty()) {
r = State.MOVING;
if (outQueue.get(0).getsourceFloor() == currentFloor) {
queue.addInternalRequest(outQueue.get(0).getdestinationFloor());
outQueue.remove(0);
r = State.STOPPED;
}
}
else if (!innerQueue.isEmpty() && outQueue.isEmpty()) {
r = State.MOVING;
if (innerQueue.get(0) == currentFloor) {
innerQueue.remove(0);
r = State.STOPPED;
}
}
if (r==State.STOPPED) {
openDoors();
}
}
public int getNextFloor() {
int currentFloor = elevator.getCurrentFloor();
if (elevator.getDirection() == Direction.UP) {
return currentFloor + 1;
} else if (elevator.getDirection() == Direction.DOWN) {
return currentFloor - 1;
}
return currentFloor;
}
public void openDoors() {
LinkedList<Integer> innerQueue = queue.getInternalRequests();
LinkedList<Passenger> outQueue = queue.getExternalRequests();
System.out.println("Open Door # Floor " + elevator.getCurrentFloor());
System.out.print("Close Door");
if(!innerQueue.isEmpty()||!outQueue.isEmpty()){
System.out.printf("\n");
}
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String data; //输入数据:字符串
int floor = 0;
Direction direction = null;
int minFloor,maxFloor; //电梯最低楼层、最高楼层
int sourceFloor,destinationFloor;
String request = ""; //提取出的乘客请求字符串
ArrayList<String> list = new ArrayList<>(); //用于接收用户输入的数组
data = input.next();
while(!data.equalsIgnoreCase("End")){ //输入以“end”结束
list.add(data);
data = input.next();
}
minFloor = Integer.parseInt(list.get(0));//第一行,电梯最低楼层
maxFloor = Integer.parseInt(list.get(1));//第二行,电梯最高楼层
Elevator elevator = new Elevator(minFloor, maxFloor);//创建电梯对象
RequestQueue queue = new RequestQueue();
Controller controller = new Controller(elevator, queue);
for(int i = 2; i < list.size(); i++){//从第三行开始为乘客请求
request = list.get(i);
if(request.contains(",")){//外部请求
if (!request.matches("<\\d+,\\d>")) {
System.out.println("Wrong Format");
}
String[] parts = request.replaceAll("[<>]", "").split(",");
sourceFloor = Integer.parseInt(parts[0].trim());
destinationFloor = Integer.parseInt(parts[1].trim());
if(elevator.isValidFloor(destinationFloor)&&elevator.isValidFloor(sourceFloor)){
queue.addExternalRequest(sourceFloor,destinationFloor);//外部请求入队
}
}else{
if (!request.matches("<\\d+>")) {//内部请求
System.out.println("Wrong Format");
}
floor = Integer.parseInt(request.replaceAll("[<>]", ""));
if(elevator.isValidFloor(floor)){
queue.addInternalRequest(floor);//内部请求入队
}
}
}
while (!queue.getInternalRequests().isEmpty() || !queue.getExternalRequests().isEmpty()) {
controller.processRequests(); //一次性处理所有的内、外部乘客请求
}
input.close();
}
}
类图

分析
点击查看
类和接口
Elevator类
属性:
currentFloor:当前楼层。
direction:电梯运行方向:UP、DOWN或IDLE。
state:电梯状态,可能是MOVING`或STOPPING。
maxFloor和minFloor:电梯可运行的最大和最小楼层。
方法:
构造函数:初始化电梯。
getCurrentFloor()、setCurrentFloor()、getDirection()、setDirection()、getState()、setState():获取和设置电梯的当前状态。
getMaxFloor()、getMinFloor():获取电梯的最大和最小楼层。
isValidFloor():检查给定楼层是否有效。
Direction枚举
定义了电梯可能的运行方向:UP、DOWN和IDLE。
State枚举
定义了电梯的状态:MOVING和STOPPING。
Passenger类
属性:
sourceFloor:乘客的起始楼层。
destinationFloor:乘客的目标楼层。
方法:
构造函数:初始化乘客。
getSourceFloor()、setSourceFloor()、getDestinationFloor()、setDestinationFloor():获取和设置乘客的起始和目标楼层。
getDirection():根据起始和目标楼层计算乘客的移动方向。
RequestQueue类
属性:
internalRequests和externalRequests:内部和外部请求的队列。
方法:
getInternalRequests()、getExternalRequests():获取内部和外部请求。
addInternalRequest()、addExternalRequest():添加内部和外部请求。
Controller类
属性:
elevator:电梯实例。
queue:请求队列。
方法:
构造函数:初始化控制器。
processRequests()、determineDirection()、move()、shouldStop()、getNextFloor()、openDoors():处理请求、确定方向、移动电梯、判断是否停止、获取下一个楼层和打开门。
Main类
方法:
main():程序的入口点。
报表

分析
点击查看
行数(Lines):366 行代码。
语句数(Statements):201 个语句。
分支语句百分比(Percent Branch Statements):19.4%,表示代码中条件分支语句的比例。
方法调用语句数(Method Call Statements):158 个方法调用。
带注释的行百分比(Percent Lines with Comments):3.3%,代码注释的比例较低。
类和接口数(Classes and Interfaces):7 个类或接口。
每个类的方法数(Methods per Class):平均每个类有 4.00 个方法。
每个方法的平均语句数(Average Statements per Method):5.46 个语句。
最复杂方法的行数(Line Number of Most Complex Method):192 行,`Controller.shouldStop()`方法。
最复杂方法的名称(Name of Most Complex Method):`Controller.shouldStop()`。
最大复杂度(Maximum Complexity):35,表示方法的圈复杂度。
最深代码块的行数(Line Number of Deepest Block):211 行。
最大代码块深度(Maximum Block Depth):6 层。
平均代码块深度(Average Block Depth):2.45 层。
平均复杂度(Average Complexity):3.64。
- 三·踩坑心得
(1)第一次题目集
1.代码运行逻辑的考虑:刚开始看到题目要求后便不知道如何下手,对于电梯上下运行逻辑不了解,只能先按自己的逻辑来写,然而多次提交只是提示运行超时。直到老师发了LOOK调度算法(一种电梯调度策略,其核心逻辑为:电梯仅在当前运行方向上响应请求,若该方向无请求则切换方向),才有了具体方向。修改的过程中得出超时原因:将现在代码的determineDirection、process等方法混杂在一起。
解决方法:将process方式重新分为多种方式即可.
2.LinkedList的正确使用:对于在使用LinkedList时,发现outQueue的<>中需要重新定义。同时对于LinkedList链表的应用有一些缺口,忽略了get(0)若无此项的情况。
解决方法:定义内部类Request,同时检查isEmpty()。
3.电梯运行逻辑阐述方式:解决大方向问题后,发现调试时得到的运行结果与题目不符,显示答案错误。说明我定义的逻辑错误,需要重新设立。
解决方法:我先将电梯的运行情况拆分,只有内部请求、只有外部请求和内外都有,先分析电梯方向,对于只有一种的,方向指向链表首项;两种的,先看是否有原方向,若有,则不变,反之则改变;然后再分析停靠。我将所有情况与纸上列出,发现除了2种特殊情况其余是按方向运行后楼层一致则停靠,只有内外请求在电梯同向时、内部请求距离大于外部请求、外部请求方向与电梯相异时,先停靠内部请求。因此,我将这两种情况单独用if else表示,完成设计。
4.代码注释问题:只有主类中添加了注释,而判断电梯运行方向的方法、电梯的停靠和请求队列的移除,这些复杂的方法并没有注释,这就会导致当自己再次阅读代码时,会变得很吃力。
解决方法:增加注释,使自己或他人能读懂代码。
(2)第二次题目集
1.代码注释问题:只有主类中添加了注释,而判断电梯运行方向的方法、电梯的停靠和请求队列的移除,这些复杂的方法并没有注释,这就会导致当自己再次阅读代码时,会变得很吃力。
解决方法:增加注释,使自己或他人能读懂代码。
2.类的使用:根据题目给的类图,我将前题目集的Elevator类进行分割,但Enum等类不知道如何书写和调用。
解决方法:在网上进行查找,进行学习,使用。
3.整体代码的修改:我先是按照题目给的类图和代码进行修改,于此同时,需要将代码转换成正确形式,同时对于不同类不同方法的调用也要进行修改。刚开始总是修改不完全,显示编译错误,后来不断改进,达到没有编译错误。
解决方法:根据提示和类图将错误的代码修改。
4.电梯运行逻辑阐述方式:本来我打算将电梯逻辑的阐述方式进行改变,但我进行了多次修改后,总是答案错误,于是我重新修改原阐述方法。
解决方式:将电梯的运行情况拆分,只有内部请求、只有外部请求和内外都有,先分析电梯方向,对于只有一种的,方向指向链表首项;两种的,先看是否有原方向,若有,则不变,反之则改变;然后再分析停靠。我将所有情况与纸上列出,发现除了2种特殊情况其余是按方向运行后楼层一致则停靠,只有内外请求在电梯同向时、内部请求距离大于外部请求、外部请求方向与电梯相异时,先停靠内部请求。因此,我将这两种情况单独用if else表示,完成设计。同时根据新的类,进行合适的修改。
5.电梯运行逻辑的考虑:我将代码按照新类图修改为新的形式后,仍为答案错误;我发现新加入的删除重复输入有问题,进行修改后仍为答案错误,但对一半错一半;我将不同的测试输入进行调试,发现电梯的逻辑中floor范围固定为从1开始,无论minFloor情况,修改后答案正确。
解决方法:将addExternalQueue进行修改,条件需符合情况;将电梯逻辑符合现实,其不一定从1楼开始,也可能从1楼结束(地下电梯)。
(3)第三次题目集
1.代码注释问题:只有主类中添加了注释,而判断电梯运行方向的方法、电梯的停靠和请求队列的移除,这些复杂的方法并没有注释,这就会导致当自己再次阅读代码时,会变得很吃力。
解决方法:增加注释,使自己或他人能读懂代码。
2.细节问题:在第二次作业集的基础上,第三次题目更易修改,将ExternalRequest改为Passenger,同时在shouldStop中进行两个链表之间的交互,但当我全部修改完后显示答案错误,调试时发现输出结果在一些地方对不上;进行多次调试后发现是外部请求的问题,我翻代码后发现getDestinationFloor返回sourceFloor,导致错误。
解决方法:改正方法getDestinationFloor。
- 四·改进建议
(1)第一次题目集
1.做到单一职责原则:按照java面向对象程序设计,来进行多种类的结合使用。先构思出具体类图,再以此写代码,在写代码的过程中,进行不断修改。
2.改进电梯运行逻辑:我的代码中对于电梯逻辑的阐述过于复杂,同时不符合正常形式,正如老师发的用if进行的需要修改表示形式,所以进行下次题目时需要改变表示,使其更符合正常LOOK调度算法。
3.添加合适的注释,增强代码可读性:这段代码全部看下来,只有主类中添加了注释,而判断电梯运行方向的方法、电梯的停靠和请求队列的移除,这些复杂的方法并没有注释。这就会导致当自己再次阅读代码时,会变得很吃力,所以需要给出合适的代码注释,增强代码的可读性。
(2)第二次题目集
1.添加合适的注释,增强代码可读性:这段代码全部看下来,只有主类中添加了注释,而判断电梯运行方向的方法、电梯的停靠和请求队列的移除,这些复杂的方法并没有注释。这就会导致当自己再次阅读代码时,会变得很吃力,所以需要给出合适的代码注释,增强代码的可读性。
2.学习新知识:在Java中,仍有许多新知识。建议学习时,结合实际例子理解。
3.整体代码的修改:在修改代码时,可以采用增量开发的方式,每次只修改一小部分代码,然后进行编译和测试。这样可以及时发现并解决问题,避免一次性修改过多导致难以定位错误。
4.注重现实逻辑:在修改逻辑时,可以先用伪代码或流程图重新设计逻辑,确保逻辑的正确性后再进行代码实现。同时,可以编写测试点来验证逻辑的正确性,避免因逻辑错误导致答案错误。
5.边界条件的处理:在处理边界条件时,要特别小心。例如,电梯的楼层范围可能从任意楼层开始或结束,需要在代码中明确处理这些情况。
(3)第三次题目集
1.添加合适的注释,增强代码可读性:这段代码全部看下来,只有主类中添加了注释,而判断电梯运行方向的方法、电梯的停靠和请求队列的移除,这些复杂的方法并没有注释。这就会导致当自己再次阅读代码时,会变得很吃力,所以需要给出合适的代码注释,增强代码的可读性。
2.注意细节:随着学习的深入,java代码会更加复杂,如果在细节处出现错误,可能会导致整个代码的崩溃;所以应该更加注重细节之处。
- 五·总结
(1)收获
1.深入理解电梯调度算法:通过三次题目集的实践,对电梯调度算法(如LOOK调度算法)有了更深入的理解。学会了如何将复杂的电梯运行逻辑拆分成不同场景
- 掌握LinkedList的使用:学会了如何正确使用 LinkedList,包括定义内部类(如 Request )和处理边界情况(如 isEmpty() 检查)。这不仅提高了代码的健壮性,也让你对集合类的使用更加熟练。
- 提升代码注释的能力:意识到注释的重要性,这不仅将了代码的可读性,也方便了后续的维护和调试。
- 掌握面向对象设计原则:学会了如何按照面向对象设计原则(如单一职责原则)进行代码设计。通过构思类图,将功能分解到多个类中,每个类只负责一个功能,提高了代码的可维护性和可扩展性。
- 增强调试和测试能力:通过多次调试和测试,学会了如何逐步排查问题,特别是处理边界条件和细节问题。这不仅提高了代码的鲁棒性,也让你对测试的重要性有了更深刻的认识。
(2)进一步学习及研究
1.优化代码性能:在题目集中,遇到了代码运行超时的问题,虽然通过优化逻辑解决了问题,但在性能优化方面还可以进一步学习。
2.处理复杂逻辑和边界条件:在处理复杂逻辑和边界条件时,已经积累了一定的经验,但仍需要进一步提升。
3.学习新知识和新技术:意识到Java中还有很多新知识需要学习和积累。
4.提升代码注释的能力:意识到注释的重要性,这不仅将了代码的可读性,也方便了后续的维护和调试,但注释仍不足。
总而言之,通过这三次题目集的实践,在编程能力上有了显著提升,从C开始转变到java,特别是在面向对象设计原则的应用、调试和测试能力等方面。然而,仍有一些地方需要进一步学习和研究,如代码性能的优化、复杂逻辑的处理,以及新知识和新技术的学习。未来应不断总结经验,提升编程技能。

浙公网安备 33010602011771号