电梯程序总结blog

一、前言
第一阶段的Java大作业这三次题目集层层迭代,于我而言是很大的挑战,考察了我的题目理解能力、逻辑思维以及类设计。不仅大大促进了我对Java语法的适应,也让我对面向对象编程有了初步的了解,积累了宝贵的实战经验。
二、 设计与分析
第一次题目集

点击查看代码

import java.util.Scanner;
import java.util.LinkedList;
import java.util.Queue;

class Elevator {
    private int minFloor, maxFloor, currentFloor;
    private String direction, state;
    private Queue<Integer> internalRequests;
    private Queue<Integer> externalRequests;
    private Queue<String> externalRequestsDir;
    
    public Elevator(int minFloor, int maxFloor) {  
        this.minFloor = minFloor;
        this.maxFloor = maxFloor;
        this.currentFloor = minFloor;
        this.direction = "IDLE";
        this.state = "STOP";
        this.internalRequests = new LinkedList<>();
        this.externalRequests = new LinkedList<>();
        this.externalRequestsDir = new LinkedList<>();
    }
    
    public void addIn(int f) {
        internalRequests.add(f);
    }
    
    public void addOut(int f, String dir) {
        externalRequests.add(f);
        externalRequestsDir.add(dir);
    }
    
    public void run() {
        while (!(internalRequests.isEmpty() && externalRequests.isEmpty())) {
            if (state.equals("STOP")) {
                determine();
            }
            if (direction.equals("UP")) {
                currentFloor++;
                System.out.printf("Current Floor: %d Direction: UP\n", currentFloor);
            }
            if (direction.equals("DOWN")) {
                currentFloor--;
                System.out.printf("Current Floor: %d Direction: DOWN\n", currentFloor);
            }
            judge();
        }
    }
    
    public void determine() {
        if (direction.equals("IDLE")) {  
            if (!externalRequests.isEmpty()) direction = "UP";
            state = "MOVE";
            System.out.printf("Current Floor: %d Direction: UP\n", currentFloor);
        }
        else if (direction.equals("UP")) {
            if (!internalRequests.isEmpty()) {
                if (internalRequests.element() > currentFloor) {
                    state = "MOVE";
                }
                else {
                    if (externalRequests.isEmpty()) {
                        state = "MOVE";
                        direction = "DOWN";
                    }
                    else {
                        int m = parseFloor(externalRequests.peek());
                        if (m > currentFloor) state = "MOVE";
                        else {
                            state = "MOVE";
                            direction = "DOWN";
                        }
                    }
                }
            }
            if (internalRequests.isEmpty()) {
                int m = parseFloor(externalRequests.peek());
                if (m > currentFloor) state = "MOVE";
                else {
                    state = "MOVE";
                    direction = "DOWN";
                }
            }
        }
        else if (direction.equals("DOWN")) {
            if (!internalRequests.isEmpty()) {
                if (internalRequests.element() < currentFloor) {
                    state = "MOVE";
                }
                else {
                    if (externalRequests.isEmpty()) {
                        state = "MOVE";
                        direction = "UP";
                    }
                    else {
                        int m = parseFloor(externalRequests.peek());
                        if (m < currentFloor) state = "MOVE";
                        else {
                            state = "MOVE";
                            direction = "UP";
                        }
                    }
                }
            }
            if (internalRequests.isEmpty()) {
                int m = parseFloor(externalRequests.peek());
                if (m < currentFloor) state = "MOVE";
                else {
                    state = "MOVE";
                    direction = "UP";
                }
            }
        }
    }
    
    private int parseFloor(int floor) {  
        return floor; 
    }
    
    public void judge() {
        int t = 0;
        if (!internalRequests.isEmpty()) {
            if (internalRequests.element() == currentFloor) {
                internalRequests.remove();
                t = 1;
            }
            if (!externalRequests.isEmpty()) {
                int m = parseFloor(externalRequests.peek());
                if (m == currentFloor) {
                    if (externalRequestsDir.peek().equals(direction)) {
                        externalRequests.remove();
                        externalRequestsDir.remove();
                        t = 1;
                    }
                    else {
                        if (!internalRequests.isEmpty()) {
                            if ((direction.equals("UP") && internalRequests.element() < currentFloor) || 
                                (direction.equals("DOWN") && internalRequests.element() > currentFloor)) {
                                externalRequests.remove();
                                externalRequestsDir.remove();
                                t = 1;
                            }
                        }
                    }
                }
            }
        }
        else {
            if (!externalRequests.isEmpty()) {
                int m = parseFloor(externalRequests.peek());
                if (m == currentFloor) {
                    externalRequests.remove();
                    externalRequestsDir.remove();
                    t = 1;
                }
            }
        }
        if (t == 1) {
            System.out.printf("Open Door # Floor %d\n", currentFloor);
            System.out.printf("Close Door\n");
            state = "STOP";
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int min = scanner.nextInt();
        int max = scanner.nextInt();
        scanner.nextLine();
        Elevator elevator = new Elevator(min, max);
        while (true) {
            String request = scanner.nextLine();
            if (request.equalsIgnoreCase("end")) break;
            else {
                if (request.matches("<\\d+>")) {
                    int floor = Integer.parseInt(request.substring(1, request.length()-1));
                    elevator.addIn(floor);
                } 
                else if (request.matches("<\\d,UP>")) {
                    int floor = Integer.parseInt(request.substring(1, request.indexOf(',')));
                    elevator.addOut(floor, "UP");
                }
                else if (request.matches("<\\d+,DOWN>")) {
                    int floor = Integer.parseInt(request.substring(1, request.indexOf(',')));
                    elevator.addOut(floor, "DOWN");
                }
            }
        }
        elevator.run();
        scanner.close();
    }
}

类图:

类设计:

  1. Elevator类:设计了电梯的最小楼层数(默认为1层)、最大楼层数、当前楼层、运行方向、运行状态等属性,以及储存内部请求楼层数的链表,储存外部请求楼层数的链表,储存外部请求方向的链表。功能有向内部链表末尾加入节点(addIn),向外部链表末尾加入节点(addOut),判断方向(determine),运行(run),需要在当前楼层停靠并开关门(judge)等
  2. Main类:主要使用正则表达式将读入的数据进行处理
点击查看SourceMontor的生成报表内容

分析与心得:

  • 方向判断逻辑复杂:determine方法中多层嵌套的if-else语句用于判断电梯方向,代码可读性较差,且在处理内外请求优先级时逻辑不够清晰。
  • 请求匹配策略单一:judge方法仅简单判断当前楼层是否存在请求,未考虑同向请求优先处理的原则,可能导致电梯频繁改变方向,降低运行效率。
  • 方法职责不单一:determine方法同时承担方向判断和状态切换逻辑,违反单一职责原则;judge方法将请求匹配与开关门操作耦合,增加了维护成本。

第二次题目集

点击查看代码
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int minfloor = scanner.nextInt();
        int maxfloor = scanner.nextInt();
        Elevator elevator = new Elevator(minfloor, maxfloor);

        RequestQueue requestQueue = new RequestQueue().getQueueInstance(scanner, elevator.getMinFloor(), elevator.getMaxFloor());

        Controller controller = new Controller(elevator, requestQueue);
        controller.processRequests();
    }
}

class RequestQueue {
    private LinkedList<Integer> internalRequests = new LinkedList<>();
    private LinkedList<ExternalRequest> externalRequests = new LinkedList<>();

    public RequestQueue() {
    }

    public RequestQueue getQueueInstance(Scanner scanner, int minFloor, int maxFloor) {
        RequestQueue requestQueue = new RequestQueue();
        while (scanner.hasNextLine()) {
            String request = scanner.nextLine().trim();
            if (request.equalsIgnoreCase("end")) {
                break;
            }
            if (!request.isEmpty()) {
                if (request.matches("<\\d+>")) {
                    int floor = Integer.parseInt(request.substring(1, request.length() - 1));
                    if (isValidFloor(floor, minFloor, maxFloor)) {
                        requestQueue.addInternalRequest(floor);
                    }
                } else if (request.matches("<\\d+,UP>")) {
                    int floor = Integer.parseInt(request.substring(1, request.indexOf(',')));
                    if (isValidFloor(floor, minFloor, maxFloor)) {
                        requestQueue.addExternalRequest(floor, Direction.UP);
                    }
                } else if (request.matches("<\\d+,DOWN>")) {
                    int floor = Integer.parseInt(request.substring(1, request.indexOf(',')));
                    if (isValidFloor(floor, minFloor, maxFloor)) {
                        requestQueue.addExternalRequest(floor, Direction.DOWN);
                    }
                }
            }
        }
        return requestQueue;
    }

    private boolean isValidFloor(int floor, int minFloor, int maxFloor) {
        return floor >= minFloor && floor <= maxFloor;
    }

    public LinkedList<Integer> getInternalRequests() {
        return internalRequests;
    }

    public void setInternalRequests(LinkedList<Integer> internalRequests) {
        this.internalRequests = internalRequests;
    }

    public LinkedList<ExternalRequest> getExternalRequests() {
        return externalRequests;
    }

    public void setExternalRequests(LinkedList<ExternalRequest> externalRequests) {
        this.externalRequests = externalRequests;
    }

    void addInternalRequest(int floor) {
        internalRequests.add(floor);
    }

    void addExternalRequest(int floor, Direction direction) {
        externalRequests.add(new ExternalRequest(floor, direction));
    }
}

class Controller {
    private Elevator elevator;
    private RequestQueue queue;

    public Controller() {
    }

    public Controller(Elevator elevator, RequestQueue queue) {
        this.elevator = elevator;
        this.queue = queue;
    }

    public Elevator getElevator() {
        return elevator;
    }

    public void setElevator(Elevator elevator) {
        this.elevator = elevator;
    }

    public RequestQueue getQueue() {
        return queue;
    }

    public void setQueue(RequestQueue queue) {
        this.queue = queue;
    }

    public void processRequests() {
        System.out.println("Current Floor: " + elevator.getCurrentFloor() + " Direction: UP");
        while (!queue.getInternalRequests().isEmpty() || !queue.getExternalRequests().isEmpty()) {
            determineDirection();
            move();
            System.out.println("Current Floor: " + elevator.getCurrentFloor() + " Direction: " + elevator.getDirection());

            if (shouldStop(elevator.getCurrentFloor())) {
                openDoors();
                removeRequests(elevator.getCurrentFloor());
            }
        }
        elevator.setState(State.STOPPED);
    }

    private void determineDirection() {
        if (elevator.getDirection() == Direction.IDLE) {
            if (!queue.getExternalRequests().isEmpty()) {
                elevator.setDirection(Direction.UP);
            }
            elevator.setState(State.MOVING);
            return;
        }

        if (!queue.getInternalRequests().isEmpty()) {
            int internalFirst = queue.getInternalRequests().peek();
            if (elevator.getDirection() == Direction.UP) {
                if (internalFirst <= elevator.getCurrentFloor()) {
                    if (queue.getExternalRequests().isEmpty()) {
                        elevator.setDirection(Direction.DOWN);
                    } else {
                        int externalFirst = queue.getExternalRequests().peek().getFloor();
                        if (externalFirst <= elevator.getCurrentFloor()) {
                            elevator.setDirection(Direction.DOWN);
                        }
                    }
                }
            } else if (elevator.getDirection() == Direction.DOWN) {
                if (internalFirst >= elevator.getCurrentFloor()) {
                    if (queue.getExternalRequests().isEmpty()) {
                        elevator.setDirection(Direction.UP);
                    } else {
                        int externalFirst = queue.getExternalRequests().peek().getFloor();
                        if (externalFirst >= elevator.getCurrentFloor()) {
                            elevator.setDirection(Direction.UP);
                        }
                    }
                }
            }
        } else {
            if (!queue.getExternalRequests().isEmpty()) {
                int externalFirst = queue.getExternalRequests().peek().getFloor();
                if (elevator.getDirection() == Direction.UP && externalFirst <= elevator.getCurrentFloor()) {
                    elevator.setDirection(Direction.DOWN);
                } else if (elevator.getDirection() == Direction.DOWN && externalFirst >= elevator.getCurrentFloor()) {
                    elevator.setDirection(Direction.UP);
                }
            }
        }
    }

    private void move() {
        elevator.setState(State.MOVING);
        int nextFloor = getNextFloor();
        if (elevator.isValidFloor(nextFloor)) {
            elevator.setCurrentFloor(nextFloor);
        }
    }

    private boolean shouldStop(int floor) {
        if (!queue.getInternalRequests().isEmpty() && queue.getInternalRequests().peek() == floor) {
            return true;
        }

        if (!queue.getExternalRequests().isEmpty()) {
            ExternalRequest firstExternal = queue.getExternalRequests().peek();
            if (firstExternal.getFloor() == floor) {
                if (firstExternal.getDirection() == elevator.getDirection()) {
                    return true;
                }
                if (queue.getInternalRequests().isEmpty()) {
                    return true;
                }
                if ((elevator.getDirection() == Direction.UP && queue.getInternalRequests().peek() < floor) ||
                    (elevator.getDirection() == Direction.DOWN && queue.getInternalRequests().peek() > floor)) {
                    return true;
                }
            }
        }
        return false;
    }

    private int getNextFloor() {
        if (elevator.getDirection() == Direction.UP) {
            return elevator.getCurrentFloor() + 1;
        } else if (elevator.getDirection() == Direction.DOWN) {
            return elevator.getCurrentFloor() - 1;
        }
        return elevator.getCurrentFloor();
    }

    private int getClosest(int a, int b) {
        int x = Math.abs(a - elevator.getCurrentFloor());
        int y = Math.abs(b - elevator.getCurrentFloor());
        if (x <= y) {
            return a;
        } else {
            return b;
        }
    }

    private void openDoors() {
        elevator.setState(State.STOPPED);
        System.out.println("Open Door # Floor " + elevator.getCurrentFloor());
        System.out.println("Close Door");
    }

    private void removeRequests(int currentFloor) {
        // Remove internal requests
        while (!queue.getInternalRequests().isEmpty() && queue.getInternalRequests().peek() == currentFloor) {
            queue.getInternalRequests().removeFirst();
        }

        // Remove external requests
        while (!queue.getExternalRequests().isEmpty() && queue.getExternalRequests().peek().getFloor() == currentFloor) {
            ExternalRequest request = queue.getExternalRequests().peek();
            if (request.getDirection() == elevator.getDirection()) {
                queue.getExternalRequests().removeFirst();
            } else if (queue.getInternalRequests().isEmpty() || 
                      (elevator.getDirection() == Direction.UP && queue.getInternalRequests().peek() < currentFloor) ||
                      (elevator.getDirection() == Direction.DOWN && queue.getInternalRequests().peek() > currentFloor)) {
                queue.getExternalRequests().removeFirst();
            } else {
                break;
            }
        }
    }
}

class Elevator {
    private int minFloor, maxFloor, currentFloor;
    private Direction direction;
    private State state;

    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 getMinFloor() {
        return minFloor;
    }

    public int getMaxFloor() {
        return maxFloor;
    }

    public boolean isValidFloor(int floor) {
        return floor >= minFloor && floor <= maxFloor;
    }
}

class ExternalRequest {
    private int floor;
    private Direction direction;

    public ExternalRequest(int floor, Direction direction) {
        this.floor = floor;
        this.direction = direction;
    }

    public int getFloor() {
        return floor;
    }

    public Direction getDirection() {
        return direction;
    }
}

enum Direction {
    UP,
    DOWN,
    IDLE
}

enum State {
    MOVING,
    STOPPED
}

类图:

类设计:

  1. (Elevator) 电梯类:
  • 属性:包含最小楼层minFloor、最大楼层maxFloor、当前楼层currentFloor、运行方向direction(枚举类型Direction)和运行状态state(枚举类型State)。通过这些属性完整描述电梯的状态信息。
  • 方法:提供获取和设置楼层、方向、状态的方法,以及判断楼层有效性的isValidFloor方法,确保电梯运行逻辑的完整性与数据合法性。
  1. (RequestQueue) 电梯请求队列类:
  • 属性:分别使用LinkedList存储内部请求队列internalRequests和外部请求队列externalRequests,其中外部请求以ExternalRequest对象形式存储,包含目标楼层和方向信息。
  • 方法:getQueueInstance方法负责解析用户输入并将请求加入对应队列,同时验证楼层有效性;addInternalRequest和addExternalRequest用于添加请求,增强了请求处理的模块化。
  1. (ExternalRequest) 外部请求类:
  • 属性:包含目标楼层floor和请求方向direction(枚举类型Direction),清晰封装外部请求的核心信息。
  • 作用:作为外部请求的载体,使请求队列能更直观地管理外部请求数据。
  1. (Controller) 控制类:
  • 属性:持有Elevator和RequestQueue对象,作为电梯运行逻辑的核心协调者。
  • 方法:
    processRequests方法驱动整个电梯运行流程,包括方向判断、楼层移动、停靠判断和请求移除;
    determineDirection方法根据内外请求情况调整电梯方向,相较于第一次题目集,逻辑更加清晰;
    shouldStop方法综合考虑内外请求和电梯运行方向,判断是否需要停靠,优化了停靠策略。
  1. (Main) 主类:
    负责初始化电梯楼层范围、创建Elevator、RequestQueue和Controller对象,并启动请求处理流程。相较于第一次题目集,将输入处理和核心逻辑分离,使Main类职责更单一,仅专注于对象初始化和流程启动。
点击查看SourceMontor的生成报表内容

分析与心得:

  • 模块化与职责分离:第二次题目集在设计上明显优于第一次,将不同功能拆分到独立的类中,降低了类之间的耦合度,提升了代码的可维护性和扩展性。
  • 逻辑优化:在determineDirection方法中,通过分层判断内外请求优先级和方向,简化了第一次题目集中复杂的嵌套逻辑,
  • 不足之处:Controller类中的processRequests方法依然包含较多核心逻辑,如方向判断、移动、停靠等,可进一步拆分至更小的方法或独立类中,遵循单一职责原则。
  • 心得:通过完成第二次题目集,我深刻体会到合理的类划分和职责分配,不仅使代码结构更清晰,也大幅降低了调试和维护的难度。同时,使用枚举类型和集合框架(如LinkedList)替代原始数据结构和自定义链表,显著提升了开发效率和代码稳定性。

第三次题目集

点击查看代码
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int minfloor = scanner.nextInt();
		int maxfloor = scanner.nextInt();
		Elevator elevator = new Elevator(minfloor, maxfloor);

		RequestQueue requestQueue = new RequestQueue().getQueueInstance(scanner);

		Controller controller = new Controller(elevator, requestQueue);
		controller.processRequests();
		scanner.close();
	}
}
class Controller {
	private Elevator elevator;
	private RequestQueue queue;

	public Controller() {
	}

	public Controller(Elevator elevator, RequestQueue queue) {
		this.elevator = elevator;
		this.queue = queue;
	}

	public Elevator getElevator() {
		return elevator;
	}

	public void setElevator(Elevator elevator) {
		this.elevator = elevator;
	}

	public RequestQueue getQueue() {
		return queue;
	}

	public void setQueue(RequestQueue queue) {
		this.queue = queue;
	}

	public void processRequests() {
		System.out.println("Current Floor: " + elevator.getCurrentFloor() + " Direction: UP");
		while (!queue.getInternalRequests().isEmpty() || !queue.getExternalRequests().isEmpty()) {
			determineDirection();
			move();
			System.out
					.println("Current Floor: " + elevator.getCurrentFloor() + " Direction: " + elevator.getDirection());
			if (shouldStop(elevator.getCurrentFloor())) {
				openDoors();
				removeRequests(elevator.getCurrentFloor());
			}
			// 如果队列已空,提前终止
			if (queue.getInternalRequests().isEmpty() && queue.getExternalRequests().isEmpty()) {
				break;
			}
		}
		elevator.setState(State.STOPPED);
	}

	private void determineDirection() {
	    if (elevator.getDirection() == Direction.IDLE) {
	        if (!queue.getExternalRequests().isEmpty()) {
	            elevator.setDirection(Direction.UP);
	        }
	        elevator.setState(State.MOVING);
	        return;
	    }

	    if (!queue.getInternalRequests().isEmpty()) {
	        int internalFirst = queue.getInternalRequests().peek().getDestinationFloor();
	        if (elevator.getDirection() == Direction.UP) {
	            if (internalFirst <= elevator.getCurrentFloor()) {
	                if (queue.getExternalRequests().isEmpty()) {
	                    elevator.setDirection(Direction.DOWN);
	                } else {
	                    int externalFirst = queue.getExternalRequests().peek().getSourceFloor();
	                    if (externalFirst <= elevator.getCurrentFloor()) {
	                        elevator.setDirection(Direction.DOWN);
	                    }
	                }
	            }
	        } else if (elevator.getDirection() == Direction.DOWN) {
	            if (internalFirst >= elevator.getCurrentFloor()) {
	                if (queue.getExternalRequests().isEmpty()) {
	                    elevator.setDirection(Direction.UP);
	                } else {
	                    int externalFirst = queue.getExternalRequests().peek().getSourceFloor();
	                    if (externalFirst >= elevator.getCurrentFloor()) {
	                        elevator.setDirection(Direction.UP);
	                    }
	                }
	            }
	        }
	    } else {
	        if (!queue.getExternalRequests().isEmpty()) {
	            int externalFirst = queue.getExternalRequests().peek().getSourceFloor();
	            if (elevator.getDirection() == Direction.UP && externalFirst <= elevator.getCurrentFloor()) {
	                elevator.setDirection(Direction.DOWN);
	            } else if (elevator.getDirection() == Direction.DOWN && externalFirst >= elevator.getCurrentFloor()) {
	                elevator.setDirection(Direction.UP);
	            }
	        }
	    }
	}

	private void move() {
		elevator.setState(State.MOVING);
		elevator.setCurrentFloor(getNextFloor());
	}
	
	private boolean shouldStop(int floor) {
	    // 检查内部请求
	    if (!queue.getInternalRequests().isEmpty()) {
	        Passenger internalReq = queue.getInternalRequests().peek();
	        if (internalReq != null && internalReq.getDestinationFloor() == floor) {
	            return true;
	        }
	    }

	    // 检查外部请求
	    if (!queue.getExternalRequests().isEmpty()) {
            Passenger externalReq = queue.getExternalRequests().peek();
            if (externalReq != null && externalReq.getSourceFloor() == floor) {
                if (externalReq.getDirection() == elevator.getDirection()) {
                    return true;
                }
                if (queue.getInternalRequests().isEmpty()) {
                    return true;
                }
                Passenger internalReq = queue.getInternalRequests().peek();
                if ((elevator.getDirection() == Direction.UP && 
                     internalReq.getDestinationFloor() < floor) ||
                   (elevator.getDirection() == Direction.DOWN && 
                     internalReq.getDestinationFloor() > floor)) {
                    return true;
                }
            }
        }
	    return false;
	}


	private int getNextFloor() {
		if (elevator.getDirection() == Direction.UP)
			return elevator.getCurrentFloor() + 1;
		else if (elevator.getDirection() == Direction.DOWN)
			return elevator.getCurrentFloor() - 1;
		return elevator.getCurrentFloor();
	}

	private int getClosest(int a, int b) {
		int x = Math.abs(a - elevator.getCurrentFloor());
		int y = Math.abs(b - elevator.getCurrentFloor());
		if (x <= y) {
			return a;
		} else {
			return b;
		}
	}

	private void openDoors() {
		elevator.setState(State.STOPPED);
		System.out.println("Open Door # Floor " + elevator.getCurrentFloor());
		System.out.println("Close Door");
	}

	private void removeRequests(int currentFloor) {
		if (!queue.getInternalRequests().isEmpty()
				&& queue.getInternalRequests().peek().getDestinationFloor() == currentFloor) {
			queue.getInternalRequests().removeFirst();
			return;
		}
		if (!queue.getExternalRequests().isEmpty()
				&& queue.getExternalRequests().peek().getSourceFloor() == currentFloor) {
			Passenger p = new Passenger(queue.getExternalRequests().peek().getDestinationFloor());
			queue.addInternalRequest(p);
			queue.getExternalRequests().removeFirst();
			return;
		}
	}

}

class Passenger {
	private Integer sourceFloor = null;//源楼层
	private Integer destinationFloor = null;//目标层
	public Passenger() {
	}
	public Passenger(Integer sourceFloor, Integer destinationFloor) {
		this.sourceFloor = sourceFloor;
		this.destinationFloor = destinationFloor;
	}
	public Passenger(Integer destinationFloor) {
		this.destinationFloor = destinationFloor;
	}
	public Integer getSourceFloor() {
		return sourceFloor;
	}
	public void setSourceFloor(Integer sourceFloor) {
		this.sourceFloor = sourceFloor;
	}
	public Integer getDestinationFloor() {
		return destinationFloor;
	}
	public void setDestinationFloor(Integer destinationFloor) {
		this.destinationFloor = destinationFloor;
	}
	public Direction getDirection() {
        if (sourceFloor != null && destinationFloor != null) {
            if (sourceFloor > destinationFloor) {
                return Direction.DOWN;
            } else if (sourceFloor < destinationFloor) {
                return Direction.UP;
            }
        }
        return Direction.IDLE;
    }

}
class RequestQueue {
	private LinkedList<Passenger> internalRequests = new LinkedList<>();
	private LinkedList<Passenger> externalRequests = new LinkedList<>();

	public RequestQueue() {
	}

	public RequestQueue getQueueInstance(Scanner scanner) {
		while (scanner.hasNextLine()) {
			String request = scanner.nextLine().trim();
			if (request.equalsIgnoreCase("end")) {
				break;
			}
			if (!request.isEmpty()) {
				if (request.matches("<\\d+>")) {
					int destinationFloor = Integer.parseInt(request.substring(1, request.length() - 1));
					Passenger passenger = new Passenger(destinationFloor);
					this.addInternalRequest(passenger);
				} else if (request.matches("<\\d+,\\d+>")) {
					String[] parts = request.substring(1, request.length() - 1).split(",");
					int currentFloor = Integer.parseInt(parts[0]);
					int destinationFloor = Integer.parseInt(parts[1]);
					Passenger passenger = new Passenger(currentFloor,destinationFloor);
					this.addExternalRequest(passenger);
				}
			}
		}
		return this;
	}

	public LinkedList<Passenger> getInternalRequests() {
		return internalRequests;
	}

	public void setInternalRequests(LinkedList<Passenger> internalRequests) {
		this.internalRequests = internalRequests;
	}

	public LinkedList<Passenger> getExternalRequests() {
		return externalRequests;
	}

	public void setExternalRequests(LinkedList<Passenger> externalRequests) {
		this.externalRequests = externalRequests;
	}
    public void addInternalRequest(Passenger passenger) {
		 if (!internalRequests.contains(passenger.getDestinationFloor())) {
		        internalRequests.add(passenger);
		}
	}

	public void addExternalRequest(Passenger passenger) {
		externalRequests.add(passenger);
	}
}
class Elevator {
    private int minFloor, maxFloor, currentFloor;
    private Direction direction;
    private State state;
   
    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) {
		if (currentFloor >= minFloor && currentFloor <= maxFloor) {
            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 getMinFloor() {
		return minFloor;
	}


	public int getMaxFloor() {
		return maxFloor;
	}
	public boolean isValidFloor(int floor) {
        return floor >= minFloor && floor <= maxFloor;
    }

}
enum Direction{
	UP,
	DOWN,
	IDLE
}
enum State{
	MOVING,
	STOPPED
}

类图

类设计

  1. (Elevator) 电梯类
  • 属性:与第二次题目集类似,包含最小楼层minFloor、最大楼层maxFloor、当前楼层currentFloor、运行方向direction(枚举类型Direction)和运行状态state(枚举类型State) 。新增了对currentFloor设置时的楼层范围校验,保证电梯楼层数据始终处于合法区间。
  • 方法:除了基本的获取和设置属性方法,以及判断楼层有效性的isValidFloor方法外,在setCurrentFloor方法中加入了合法性判断逻辑,增强了数据的准确性和程序的健壮性。
  1. (RequestQueue) 电梯请求队列类
  • 属性:使用LinkedList分别存储内部请求队列internalRequests和外部请求队列externalRequests,队列元素类型为Passenger,Passenger类封装了乘客的源楼层和目标楼层信息,相比第二次题目集,能更全面地描述请求内容。
  • 方法:getQueueInstance方法用于解析用户输入并将请求加入对应队列,同时进行输入格式校验;addInternalRequest方法增加了对重复目标楼层请求的过滤逻辑,避免无效请求堆积;addExternalRequest方法则负责添加外部乘客请求。
  1. (Passenger) 乘客类
  • 属性:包含源楼层sourceFloor和目标楼层destinationFloor,用于记录乘客的起始和目标位置。通过getDirection方法可根据源楼层和目标楼层自动计算出行方向,方便电梯调度逻辑判断。
  • 作用:作为请求队列的基本元素,将乘客请求信息进行封装,使请求处理逻辑更具语义化和可扩展性。
  1. (Controller) 控制类
  • 属性:持有Elevator和RequestQueue对象,作为协调电梯运行和请求处理的核心类。
  • 方法:
    processRequests方法驱动电梯运行主流程,包括方向判断、楼层移动、停靠判断和请求移除,同时新增了在请求队列为空时提前终止循环的逻辑,提高了程序运行效率。
    determineDirection方法在判断电梯运行方向时,基于乘客的源楼层和目标楼层信息,综合考虑内外请求情况,逻辑更加严谨。
    shouldStop方法用于判断电梯是否应在当前楼层停靠,综合了内外请求、电梯运行方向以及内部请求的目标楼层等多个因素,确保停靠决策的合理性。
    removeRequests方法在处理请求移除时,将外部请求乘客转换为内部请求乘客,更好地模拟了实际电梯运行场景中的乘客运输过程。
  1. (Main) 主类:负责初始化电梯楼层范围,创建Elevator、RequestQueue和Controller对象,并启动请求处理流程。相较于前两次题目集,代码结构更加简洁明了,专注于程序的初始化和启动,进一步遵循了职责分离原则。

分析与心得:

  • 第三次题目集在功能上相比第二次有了显著扩展,引入Passenger类更细致地描述请求信息,提升了程序的实用性。
  • 不足:Controller类的部分方法(如processRequests)逻辑依然较为复杂,代码行数较多,可进一步拆分细化,提高代码的可读性和可维护性。代码中缺乏对异常情况的全面处理,例如当输入数据格式严重错误时,程序可能出现运行时异常,未进行有效的捕获和处理。

三、 采坑心得
第一次看到这个题目,觉得字好多而且占70%的分数一定很困难,尝试把题目通读了一遍,果不其然,没理解什么意思。看了排名,整个年级没人写出来,就想着先放一放。后面尝试理解题目大意后,考虑到有很多增删操作,决定使用链表,但由于不知道有LinkedList库函数可以直接使用,于是设计一个链表类,便有了如下的代码

点击查看代码
import java.util.Scanner;
class RequestNode {
    int floor;
    int direction; // 1:UP, -1:DOWN, 0:内部请求
    RequestNode next;
    
    public RequestNode(int floor, int direction) {
        this.floor = floor;
        this.direction = direction;
        this.next = null;
    }
}
class Elevator {
    private final int maxFloor;
    private final int minFloor;
    private int curFloor;
    private int direction; // 1:UP, 0:IDLE, -1:DOWN
    private int state;     // 0:STOPPED, 1:MOVING
    
    private RequestNode internalRequests;   // 内部请求链表
    private RequestNode externalRequests;    // 外部请求链表
    //构造函数
    public Elevator(int minFloor, int maxFloor) {
        this.minFloor = minFloor;
        this.maxFloor = maxFloor;
        this.curFloor = minFloor;
        this.direction = 0;
        this.state = 0;
        this.internalRequests = null;
        this.externalRequests = null;
    }
    
    // 添加请求到对应链表
    public void addRequest(String request) {
        if (request.matches("<\\d+>")) { // 内部请求
            int floor = Integer.parseInt(request.substring(1, request.length()-1));
            if(validateFloor(floor)) {
                internalRequests = appendToList(internalRequests, new RequestNode(floor, 0));
                activateElevator();
            }
        } 
        else if (request.matches("<\\d,UP>")) { // 外部上行请求
            int floor = Integer.parseInt(request.substring(1, request.indexOf(',')));
            if(validateFloor(floor)) {
                externalRequests = appendToList(externalRequests, new RequestNode(floor, 1));
                activateElevator();
            }
        }
        else if (request.matches("<\\d+,DOWN>")) { // 外部下行请求
            int floor = Integer.parseInt(request.substring(1, request.indexOf(',')));
            if(validateFloor(floor)) {
                externalRequests = appendToList(externalRequests, new RequestNode(floor, -1));
                activateElevator();
            }
        }
    }
    // 处理所有请求
    public void processRequests() {
    	System.out.println("Current Floor: 1 Direction: UP");
        while (hasPendingRequests()) {
            // 检查当前楼层是否需要停靠
            if (shouldStop(curFloor)) {
                System.out.println("Open Door # Floor " + curFloor);
                removeRequestsAtCurrentFloor();
                System.out.println("Close Door");
            }
            if(hasPendingRequests()) {
            	// 移动电梯
            	moveOneFloor();
            }
            // 检查是否需要改变方向
            checkDirectionChange();
        }
        // 无请求时回到空闲状态
        direction = 0;
        state = 0;
    }
    
    // 验证楼层有效性
    private boolean validateFloor(int floor) {
        return floor >= minFloor && floor <= maxFloor;
    }
    
    // 激活电梯(当有新的请求时)
    private void activateElevator() {
        if (state == 0 && direction == 0) {
            determineInitialDirection();
        }
    }
    
    // 确定初始方向
    private void determineInitialDirection() {
        if (hasRequestAbove(internalRequests,curFloor)||hasRequestAbove(externalRequests,curFloor)) {
            direction = 1;
        } else if (hasRequestBelow(internalRequests,curFloor)||hasRequestBelow(externalRequests,curFloor)) {
            direction = -1;
        }
        state = 1;
    }
    // 检查上方是否有请求
    private boolean hasRequestAbove(RequestNode head, int floor) {
        if (head == null) {
            return false;
        }
        RequestNode current = head;
        if (current.floor > floor) return true;
        return false;
    }
    //检查下方是否有请求
    private boolean hasRequestBelow(RequestNode head, int floor) {
        if (head == null) {
            return false;
        }
        RequestNode current = head;
        if (current.floor < floor) return true;
        return false;
    }
    // 向链表末尾添加节点
    private RequestNode appendToList(RequestNode head, RequestNode newNode) {
        if (head == null) {
            return newNode;
        }
        RequestNode current = head;
        while (current.next != null) {
            current = current.next;
        }
        current.next = newNode;
        return head;
    }
  
   
    // 判断是否有待处理请求
    private boolean hasPendingRequests() {
        return internalRequests != null || externalRequests != null;
    }
    
    // 判断是否应在当前楼层停靠
    private boolean shouldStop(int floor) {
    	
        // 检查内部请求
        if (containsFloor(internalRequests, floor)) {
            return true;
            
        }
        // 检查同方向的外部请求
        RequestNode current = externalRequests;
        if (containsFloor(externalRequests, floor)) {
        	if (direction == 0 || current.direction == direction) {
                return true;
            }
        }
        return false;
    }
    
    // 从链表中移除当前楼层所有请求
    private void removeRequestsAtCurrentFloor() {
        internalRequests = removeFromList(internalRequests, curFloor);
        externalRequests = removeFromList(externalRequests, curFloor);
    }
    
    // 从链表中删除指定楼层的所有节点
    private RequestNode removeFromList(RequestNode head, int floor) {
        RequestNode dummy = new RequestNode(0, 0);
        dummy.next = head;
        RequestNode prev = dummy;
        RequestNode current = head;
        if(current==null) {
        	return null;
        }
        if (current.floor == floor) {
            prev.next = current.next;
        }
        return dummy.next;
    }
    
    // 移动一层
    private void moveOneFloor() {
        if (direction == 1 && curFloor < maxFloor) {
            curFloor++;
        } else if (direction == -1 && curFloor > minFloor) {
            curFloor--;
        }
        
        state = 1;
        System.out.println("Current Floor: " + curFloor + " Direction: " + getDirectionString());
    }
    
    // 获取方向字符串
    private String getDirectionString() {
        switch (direction) {
            case 1: return "UP";
            case -1: return "DOWN";
            default: return "IDLE";
        }
    }
    
    // 检查是否需要改变方向
    private void checkDirectionChange() {
        if (direction == 1 && !hasRequestAbove(internalRequests,curFloor)&&!hasRequestAbove(externalRequests,curFloor)) {
            direction = -1;
        } else if (direction == -1 && !hasRequestBelow(internalRequests,curFloor)&&!hasRequestBelow(externalRequests,curFloor)) {
            direction = 1;
        }
    }
    

    // 检查链表中第一个是否为指定楼层
    private boolean containsFloor(RequestNode head, int floor) {
    	if(head==null) {
    		return false;
    	}
    	if (head.floor == floor) {
            return true;
        }
        return false;
    }
}

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
        
        // 读取楼层范围
        int minFloor = sc.nextInt();
        int maxFloor = sc.nextInt();
        
        Elevator elevator = new Elevator(minFloor, maxFloor);
        
        // 处理请求输入
        while (sc.hasNextLine()) {
            String input = sc.nextLine().trim();
            if (input.equalsIgnoreCase("end")) {
                break;
            }
            elevator.addRequest(input); 
        }
        elevator.processRequests();
	}
}

后面根据老师给的提示选择使用LinkedList库函数,但是不懂得一个节点怎么同时储存楼层数和方向,跟其他已经完成的同学交流,得知她使用了三个链表,便尝试自己写
于是有了如下代码

点击查看代码
import java.util.Scanner;
import java.util.LinkedList;
import java.util.Queue;

class Elevator {
    private final int maxFloor;
    private final int minFloor;
    private int currentFloor;
    private int direction; // 1:UP, 0:IDLE, -1:DOWN
    private int state;     // 0:STOPPED, 1:MOVING
    private Queue<Integer> internalRequests;// 内部请求链表
    private Queue<Integer> externalRequests;// 外部请求链表
    private Queue<Integer> externalRequestsDir;// 外部请求链表对应方向

   
    //构造函数
    public Elevator(int minFloor, int maxFloor) {
        this.minFloor = minFloor;
        this.maxFloor = maxFloor;
        this.currentFloor = minFloor;
        this.direction = 0;
        this.state = 0;
        this.internalRequests = new LinkedList<>();
        this.externalRequests = new LinkedList<>();
        this.externalRequestsDir = new LinkedList<>();
    }
    
    // 添加请求到对应链表
    public void addRequest(String request) {
        if (request.matches("<\\d+>")) { // 内部请求
            int floor = Integer.parseInt(request.substring(1, request.length()-1));
            if(validateFloor(floor)) {
                internalRequests.add(floor);
            }
        } 
        else if (request.matches("<\\d,UP>")) { // 外部上行请求
            int floor = Integer.parseInt(request.substring(1, request.indexOf(',')));
            if(validateFloor(floor)) {
            	externalRequests.add(floor);
            	externalRequestsDir.add(1);
            }
        }
        else if (request.matches("<\\d+,DOWN>")) { // 外部下行请求
            int floor = Integer.parseInt(request.substring(1, request.indexOf(',')));
            if(validateFloor(floor)) {
            	externalRequests.add(floor);
            	externalRequestsDir.add(-1);
            }
        }
    }
    
    public void processRequests() {
        System.out.println("Current Floor: 1 Direction: UP");
        
        while (hasPendingRequests()) {
            checkDirectionChange();
            
            if (shouldStop(currentFloor)) {
                System.out.println("Open Door # Floor " + currentFloor);
                removeRequestsAtCurrentFloor();
                System.out.println("Close Door");
            }
            
            if (hasPendingRequests()) {
                moveOneFloor();
            }
        }
        
        direction = 0;
        state = 0;
    }
    
    private boolean validateFloor(int floor) {
        if (floor < minFloor || floor > maxFloor) {
            return false;
        }
        return true;
    }
    
    void activateElevator() {
        if (state == 0 && direction == 0) {
            determineInitialDirection();
            state = 1;
        }
    }
    
    private void determineInitialDirection() {
        if (hasRequestAbove(currentFloor)) {
            direction = 1;
        } else if (hasRequestBelow(currentFloor)) {
            direction = -1;
        }
    }
    
    private boolean hasRequestAbove(int floor) {
        return hasHigherRequest(internalRequests, floor) ||
        		hasHigherRequest(externalRequests, floor);
    }
    
    private boolean hasRequestBelow(int floor) {
        return hasLowerRequest(internalRequests, floor) ||
        		hasLowerRequest(externalRequests, floor) ;
    }
    
 // 检查上方是否有请求
    private boolean hasHigherRequest(Queue<Integer> queue, int floor) {
        return !queue.isEmpty() && queue.peek() > floor;
    }

    private boolean hasLowerRequest(Queue<Integer> queue, int floor) {
        return !queue.isEmpty() && queue.peek() < floor;
    }
    
    
    private boolean hasPendingRequests() {
        return !internalRequests.isEmpty() || 
               !externalRequests.isEmpty() ;
    }
    
    private boolean shouldStop(int floor) {
        // 检查内部请求
        if (!internalRequests.isEmpty() && internalRequests.peek() == floor) {
            return true;
        }
        
        // 检查外部请求
        if (!externalRequests.isEmpty() && externalRequests.peek() == floor && externalRequestsDir.peek() == direction) {
            return true;
        } 
        
        return false;
    }
    
    private void removeRequestsAtCurrentFloor() {
        // 移除内部请求
        if (!internalRequests.isEmpty() && internalRequests.peek() == currentFloor) {
            internalRequests.poll();
        }
        
        // 移除外部请求
        if (!externalRequests.isEmpty() && externalRequests.peek() == currentFloor && externalRequestsDir.peek() == direction) {
            externalRequests.poll();
            externalRequestsDir.poll();
        }
    }
    
    private void moveOneFloor() {
        if (direction == 1 && currentFloor < maxFloor) {
            currentFloor++;
        } else if (direction == -1 && currentFloor > minFloor) {
            currentFloor--;
        }
        
        System.out.println("Current Floor: " + currentFloor + " Direction: " + getDirectionString());
    }
    
    private String getDirectionString() {
        switch (direction) {
            case 1: return "UP";
            case -1: return "DOWN";
            default: return "IDLE";
        }
    }
    
    private void checkDirectionChange() {
        if ((hasHigherRequest(externalRequests,currentFloor)&&externalRequestsDir.peek() == 1) && !hasLowerRequest(internalRequests,currentFloor)) {
            direction = 1;
        } else if ((hasLowerRequest(externalRequests,currentFloor)&&externalRequestsDir.peek() == -1) && !hasHigherRequest(internalRequests,currentFloor)) {
            direction = -1;
        }
    }
}

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
        
        // 读取楼层范围
        int minFloor = sc.nextInt();
        int maxFloor = sc.nextInt();
        
        Elevator elevator = new Elevator(minFloor, maxFloor);
        
        // 处理请求输入
        while (sc.hasNextLine()) {
            String input = sc.nextLine().trim();
            if (input.equalsIgnoreCase("end")) {
                break;
            }
            elevator.addRequest(input); 
        }
        elevator.processRequests();
	}
}
这个代码与老师最初所给的示例相符,但提交后运行超时,我在想是不是我理解题目不对。后来,根据老师给的示例我再次尝试理解题意,修改了部分逻辑。值得一提的是,在最开始我没有理清楚需要哪些方法还有方法的功能,导致修改逻辑过程非常困难。最后历经磨难终于通过了。

第二次题目并没有做逻辑上的修改,而是根据题目所给类图来进行类设计,理清楚每个类有哪些方法,每个方法干什么。在第一次题目理解的基础上,第二次相对来说就比较容易了

第三次修改了部分逻辑,外部请求不再是输入楼层数和方向,而是改为源楼层和目标楼层。我根据题目修改了部分类设计和逻辑,没有改变主体逻辑,但是没有通过后面两个测试点只拿了一般的分数。在截止前,我尝试各种边界值的测试,跟同学们交流,他们中很多人都是不大块修改就可以通过,我也尝试多次,但最终还是没能成功。

四、改进建议
减少不必要的队列操作:在处理请求队列时,避免频繁地调用peek和remove方法。以第三次题目集为例,在determineDirection和shouldStop方法中,对请求队列的操作可以先将相关请求信息提取到临时变量中,减少对队列的多次访问。如将queue.getInternalRequests().peek().getDestinationFloor()的值先赋给一个临时变量nextInternalFloor,后续使用该变量进行逻辑判断,提高代码执行效率。

优化循环逻辑:在主循环处理请求的代码中,如Controller类的processRequests方法的循环,减少循环内部不必要的计算和判断。可以在循环开始前先判断请求队列是否为空,如果为空则直接结束循环,避免进入循环后再进行多次条件判断,降低时间复杂度。
五、总结
通过完成这三次 Java 大作业题目集,我在多个方面实现了显著成长。在技术层面,从最初对题目理解的迷茫,到逐步掌握面向对象编程的核心思想,学会合理设计类和封装方法,能够根据需求不断优化代码结构与逻辑。同时,对 Java 语法的运用更加熟练,尤其是集合框架的使用,极大提升了开发效率。

在解决问题的能力上,每次作业都如同一次挑战,从最初因代码运行超时、逻辑错误而不知所措,到后来通过分析复杂度、调试代码、与同学交流等方式逐步攻克难题,学会了如何从复杂问题中抽丝剥茧,找到问题的本质并加以解决。

然而,也暴露出许多不足。在代码设计上,对设计模式的运用不够熟练,导致部分代码结构不够清晰,耦合度较高;在性能优化方面,对时间和空间复杂度的分析不够深入,未能在开发初期就做出更优的算法和数据结构选择;在错误处理上,缺乏全面的考虑,使程序在面对异常情况时不够健壮。

未来,我将深入学习设计模式,提升代码的架构设计能力;加强对算法和数据结构的学习,提高在复杂场景下选择最优解决方案的能力;养成良好的编程习惯,注重代码的规范、注释和异常处理,确保程序的稳定性和可维护性。这些经历不仅是一次学习的过程,更为我今后的编程之路奠定了坚实的基础,让我有信心面对更大的挑战。

posted @ 2025-04-19 21:46  冀宇橦  阅读(64)  评论(0)    收藏  举报