NCHU-OOP-第一次工程级项目

一、 前言与概述
此次阶段的题目主要是围绕着模拟电梯运行的程序,三次不断迭代优化程序。然后这次需要运用到正则表达式,类的设计,电梯算法等知识。

二、题目描述

点击查看代码

设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
    电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
    使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
    请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
•	电梯内乘客请求格式:<楼层数>
•	电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
•	当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
•	运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
•	运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
输入样例:
在这里给出一组输入。例如:
1
20
<3,UP>
<5>
<6,DOWN>
<7>
<3>
end
输出样例:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
Open Door # Floor 3
Close Door
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Open Door # Floor 7
Close Door
Current Floor: 6 Direction: DOWN
Open Door # Floor 6
Close Door
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door

三、题目分析
第一次为了降低难度是单类设计,将所有的方法都写在了电梯类当中。首先思考设计哪些方法,可以参考题目中提供的类图,再融入自己的思考。主要的方法是判断电梯运行方向,判断电梯是否停下来开门的方法。第二次题目要求分类设计,而且还增加了测试点。说实话我第一次程序通过存在很大的侥幸,程序的本身存在一定的逻辑漏洞。首先我在对类进行封装就遇到了一些问题,类的封装并不只是简单地将各个类的方法调整到各个类中就可以了。而是还需要考虑各个类之间的关系。如控制类与电梯类之间是关联的关系,控制类可以向电梯类发消息。一开始我没有很好地处理好类之间的关系,导致程序出现了非零返回。后来我通过一步步调试发现我程序中的bug,终于解决了非零返回。但是程序还是出现了答案错误。这说明我程序的逻辑还没有很好地契合题目的要求。于是我再次仔细地阅读题目的需求。梳理了一下逻辑,搞出了一些测试用例发现我的程序并没有给出期待的结果。之后我再根据这些测试用例修改我程序对应的逻辑。第三次的题目对类进行了修改,加入了乘客类,取消了乘客请求类。而且外部请求输入改为请求楼层加上去往的楼层。所以在输入需要进行修改,再将类进行要求的修改。因为我第一,二次将程序的逻辑完善地较好地实现了题目的要求,所以第一次提交就通过了四分之三的测试点。段老师说的还是很正确。一定要理解需求。对于第一个测试点的错误,我就是自作主张地认为修改了输入后是到达了一个楼层,是要它等于内部或外部请求的头部元素就要停下来,而忘记还需判断方向。意识到自己的问题后,对程序进行进一步的优化。

四、程序展示

第一次的程序:

点击查看代码

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Lift
{
    private int minFloor;
    private int maxFloor;
    private int currentFloor;
    private String direction;      // 表示方向
    private String status;        // 表示电梯当前的运动状态
    private String where;
    private Queue<Integer> insideRequests;    // 储存电梯内乘客要到达的楼层
    private Queue<Integer> outsideRequests;    // 储存电梯外乘客所在楼层
    private Queue<String> outsideRequestsDirection;    // 储存电梯外乘客要前往的方向

    public Lift(int minFloor, int maxFloor)
    {
        this.minFloor = minFloor;
        this.maxFloor = maxFloor;
        this.direction = "still";
        this.status = "stop";
        this.where = "outside";
        this.insideRequests = new LinkedList<>();
        this.outsideRequests = new LinkedList<>();
        this.outsideRequestsDirection = new LinkedList<>();
        this.currentFloor = minFloor;
    }

    // 添加内部乘客的请求
    public void addInsideRequest(int floorNum)
    {
        if (checkFloorNum(floorNum))
        {
            insideRequests.add(floorNum);
        }
        else
        {
            System.out.println("无效楼层请求: " + floorNum);
        }
    }

    // 添加外部乘客的请求
    public void addOutsideRequest(int floorNum, String direction)
    {
        if (checkFloorNum(floorNum))
        {
            outsideRequests.add(floorNum);
            outsideRequestsDirection.add(direction);
        }
        else
        {
            System.out.println("无效楼层请求: " + floorNum);
        }
    }

    public boolean checkFloorNum(int floorNum)
    {
        return floorNum >= minFloor && floorNum <= maxFloor;
    }

    public boolean ifStop(int floorNum)
    {
        if (!insideRequests.isEmpty() && insideRequests.peek() == floorNum)
        {
            where = "inside";
            return true;
        }
        if (!outsideRequests.isEmpty() && !outsideRequestsDirection.isEmpty()
                && outsideRequests.peek() == floorNum
                && outsideRequestsDirection.peek().equals(direction))
        {
            where = "outside";
            return true;
        }
        else if(insideRequests.isEmpty() && outsideRequests.peek() == floorNum)
        {
            where = "outside";
            return true;
        }
        return false;
    }

    public void startMoving()
    {
        if (!insideRequests.isEmpty() || !outsideRequests.isEmpty())
        {
            direction = "UP";
            status = "moving";
            System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
            move();
        }
    }

    private void determineDirection()
    {
        if (!insideRequests.isEmpty() && !outsideRequests.isEmpty())
        {
            if (insideRequests.peek() < currentFloor && outsideRequests.peek() < currentFloor)
                direction = "DOWN";
            else if (insideRequests.peek() > currentFloor && outsideRequests.peek() > currentFloor)
                direction = "UP";
            else if (outsideRequests.peek() > currentFloor && outsideRequestsDirection.peek().equals(("DOWN")))
                direction = "DOWN";
            else if (outsideRequests.peek() < currentFloor && outsideRequestsDirection.peek().equals(("UP")))
                direction = "UP";
        }
        else if (!insideRequests.isEmpty())
        {
            if (insideRequests.peek() > currentFloor)
                direction = "UP";
            else if (insideRequests.peek() < currentFloor)
                direction = "DOWN";
        }
        else if (!outsideRequests.isEmpty())
        {
            if (outsideRequests.peek() > currentFloor)
                direction = "UP";
            else if (outsideRequests.peek() < currentFloor)
                direction = "DOWN";
        }
        else
            direction = "still";
    }
    public void move()
    {
        while (!insideRequests.isEmpty() || !outsideRequests.isEmpty())
        {
            if (direction.equals("UP"))
            {
                moveUp();
            }
            else if (direction.equals("DOWN"))
            {
                moveDown();
            }
        }
        status = "stop";
        direction = "still";
    }

    private void moveUp()
    {
        while (currentFloor < maxFloor && direction.equals("UP"))
        {
            currentFloor++;
            System.out.println("Current Floor: " + currentFloor + " Direction: UP");
            if (ifStop(currentFloor))
            {
                stopHandle(currentFloor);
            }
        }
    }

    private void moveDown()
    {
        while (currentFloor > minFloor && direction.equals("DOWN"))
        {
            currentFloor--;
            System.out.println("Current Floor: " + currentFloor + " Direction: DOWN");
            if (ifStop(currentFloor))
            {
                stopHandle(currentFloor);
            }
        }
    }

    public void stopHandle(int floorNum)
    {
        status = "stop";
        System.out.println("Open Door # Floor " + floorNum);
        if (where.equals("inside"))
        {
            insideRequests.remove();
        }
        else if (where.equals("outside"))
        {
            outsideRequests.remove();
            outsideRequestsDirection.remove();
        }
        System.out.println("Close Door");
        determineDirection();
        status = "moving";
    }
}

public class Main
{
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
        int minFloor = sc.nextInt();
        int maxFloor = sc.nextInt();
        int floorNum;
        sc.nextLine();
        Lift lift = new Lift(minFloor, maxFloor);
        // 正则表达式,匹配 <数字> 或 <数字,字母> 格式
        String regex = "<(\\d+)(?:,(\\w+))?>";
        Pattern pattern = Pattern.compile(regex);
        while (true)
        {
            String input = sc.nextLine().trim(); // 去除输入行的首尾空格
            if ("end".equalsIgnoreCase(input)){break;}
            Matcher matcher = pattern.matcher(input);
            if (matcher.matches())
            {
                String direction = matcher.group(2);
                if (direction == null)// 电梯内乘客的请求
                {
                    floorNum = Integer.parseInt(matcher.group(1));
                    lift.addInsideRequest(floorNum);
                }
                else
                {
                    floorNum = Integer.parseInt(matcher.group(1));
                    lift.addOutsideRequest(floorNum, direction);
                }
            }
        }
        lift.startMoving();
        sc.close();
    }
}
第二次程序:
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Lift {
    private int minFloor;
    private int maxFloor;
    private int currentFloor;
    private String direction;      // 表示方向
    private String status;        // 表示电梯当前的运动状态

    public Lift(int minFloor, int maxFloor) {
        this.minFloor = minFloor;
        this.maxFloor = maxFloor;
        this.direction = "still";
        this.status = "stop";
        this.currentFloor = minFloor;
    }

    public int getCurrentFloor() {
        return currentFloor;
    }

    public void setCurrentFloor(int currentFloor) {
        this.currentFloor = currentFloor;
    }

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public int getMaxFloor() {
        return maxFloor;
    }

    public int getMinFloor() {
        return minFloor;
    }

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

    public boolean checkFloorNum(int floorNum) {
        return floorNum >= minFloor && floorNum <= maxFloor;
    }
}

class RequestQueue {
    private Deque<Integer> insideRequests;    // 储存电梯内乘客要到达的楼层
    private Deque<Integer> outsideRequests;    // 储存电梯外乘客所在楼层
    private Deque<String> outsideRequestsDirection;    // 储存电梯外乘客要前往的方向

    public RequestQueue() {
        this.insideRequests = new LinkedList<>();
        this.outsideRequests = new LinkedList<>();
        this.outsideRequestsDirection = new LinkedList<>();
    }

    public Deque<Integer> getInsideRequests() {
        return insideRequests;
    }

    public void setInsideRequests(Deque<Integer> insideRequests) {
        this.insideRequests = insideRequests;
    }

    public Deque<Integer> getOutsideRequests() {
        return outsideRequests;
    }

    public void setOutsideRequests(Deque<Integer> outsideRequests) {
        this.outsideRequests = outsideRequests;
    }

    public Deque<String> getOutsideRequestsDirection() {
        return outsideRequestsDirection;
    }

    public void setOutsideRequestsDirection(Deque<String> outsideRequestsDirection) {
        this.outsideRequestsDirection = outsideRequestsDirection;
    }

    // 添加内部乘客的请求
    public void addInsideRequest(int floorNum, Lift lift) {
        if (lift.checkFloorNum(floorNum)) {
            if (!insideRequests.isEmpty() && insideRequests.peekLast() == floorNum) {
            } else {
                insideRequests.add(floorNum);
            }
        }
    }

    // 添加外部乘客的请求
    public void addOutsideRequest(int floorNum, String direction, Lift lift) {
        if (lift.checkFloorNum(floorNum)) {
            if (!outsideRequests.isEmpty() && outsideRequests.peekLast() == floorNum && outsideRequestsDirection.peekLast().equals(direction)) {
            } else {
                outsideRequests.add(floorNum);
                outsideRequestsDirection.add(direction);
            }
        }
    }
}

class Controller {
    private Lift lift;
    private RequestQueue queue;

    public Controller(Lift lift, RequestQueue queue) {
        this.lift = lift;
        this.queue = queue;
    }

    public Lift getLift() {
        return lift;
    }

    public void setLift(Lift lift) {
        this.lift = lift;
    }

    public RequestQueue getQueue() {
        return queue;
    }

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

    public void startMoving() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        if (!insideRequests.isEmpty() || !outsideRequests.isEmpty()) {
            lift.setDirection("UP");
            lift.setStatus("moving");
            System.out.println("Current Floor: " + lift.getCurrentFloor() + " Direction: " + lift.getDirection());
            move();
        }
    }

    private void determineDirection() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        int currentFloor = lift.getCurrentFloor();
        String direction = lift.getDirection();
        //两个队列均不为空
        if (!insideRequests.isEmpty() && !outsideRequests.isEmpty())
        {
            if (insideRequests.peek() < currentFloor && outsideRequests.peek() < currentFloor)
                direction = "DOWN";
            else if (insideRequests.peek() > currentFloor && outsideRequests.peek() > currentFloor)
                direction = "UP";
        }
        else if (!insideRequests.isEmpty())//内部请求不为空,外部请求为空
        {
            if (insideRequests.peek() > currentFloor)
                direction = "UP";
            else if (insideRequests.peek() < currentFloor)
                direction = "DOWN";
        }
        else if (!outsideRequests.isEmpty())//外部请求不为空,内部请求为空
        {
            if (outsideRequests.peek() > currentFloor)
                direction = "UP";
            else if (outsideRequests.peek() < currentFloor)
                direction = "DOWN";
            else
            {
                if (!outsideRequests.isEmpty() && outsideRequests.peek() == currentFloor
                        && !outsideRequestsDirection.peek().equals(lift.getDirection()))
                {
                        if (outsideRequests.peek() > currentFloor)
                            direction = "UP";
                        else if (outsideRequests.peek() < currentFloor)
                            direction = "DOWN";
                }
            }
        }
        else
            direction = "still";
        lift.setDirection(direction);
    }

    public void move() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        int maxFloor = lift.getMaxFloor();
        int minFloor = lift.getMinFloor();
        while (!insideRequests.isEmpty() || !outsideRequests.isEmpty()) {
            String direction = lift.getDirection();
            int currentFloor = lift.getCurrentFloor();
            if (direction.equals("UP")) {
                while (currentFloor < maxFloor && direction.equals("UP")) {
                    currentFloor++;
                    lift.setCurrentFloor(currentFloor);
                    System.out.println("Current Floor: " + currentFloor + " Direction: UP");
                    if (ifStop(currentFloor)) {
                        stopHandle(currentFloor);
                    }
                    direction = lift.getDirection();
                }
            } else if (direction.equals("DOWN")) {
                while (currentFloor > minFloor && direction.equals("DOWN")) {
                    currentFloor--;
                    lift.setCurrentFloor(currentFloor);
                    System.out.println("Current Floor: " + currentFloor + " Direction: DOWN");
                    if (ifStop(currentFloor)) {
                        stopHandle(currentFloor);
                    }
                    direction = lift.getDirection();
                }
            }
            determineDirection();
        }
        lift.setStatus("stop");
        lift.setDirection("still");
    }

    public boolean ifStop(int floorNum) {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        String direction = lift.getDirection();

        Integer insidePeek = insideRequests.isEmpty() ? null : insideRequests.peek();
        Integer outsidePeek = outsideRequests.isEmpty() ? null : outsideRequests.peek();

        if (insidePeek != null && insidePeek == floorNum) {
            return true;
        }

        if (outsidePeek != null && !outsideRequestsDirection.isEmpty()
                && outsidePeek == floorNum
                && outsideRequestsDirection.peek().equals(direction)) {
            return true;
        }

        if (insidePeek == null && outsidePeek != null && outsidePeek == floorNum) {
            return true;
        }

        if (insidePeek != null && outsidePeek != null && outsidePeek == floorNum) {
            if (direction.equals("UP") && insidePeek < floorNum) {
                lift.setDirection(outsideRequestsDirection.peek());
                return true;
            } else if (direction.equals("DOWN") && insidePeek > floorNum) {
                lift.setDirection(outsideRequestsDirection.peek());
                return true;
            }
        }
        return false;
    }

    public void stopHandle(int floorNum) {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        lift.setStatus("stop");
        System.out.println("Open Door # Floor " + floorNum);
        // 移除当前楼层的内部请求
        if (!insideRequests.isEmpty() && insideRequests.peek() == floorNum) {
            insideRequests.remove();
        }
        // 移除当前楼层的外部请求
        if (!outsideRequests.isEmpty() && outsideRequests.peek() == floorNum) {
            outsideRequests.remove();
            outsideRequestsDirection.remove();
        }
        System.out.println("Close Door");
        determineDirection();
        lift.setStatus("moving");
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int minFloor = sc.nextInt();
        int maxFloor = sc.nextInt();
        int floorNum;
        sc.nextLine();
        Lift lift = new Lift(minFloor, maxFloor);
        RequestQueue queue = new RequestQueue();
        Controller controller = new Controller(lift, queue);
        // 正则表达式,匹配 <数字> 或 <数字,字母> 格式
        String regex = "<(\\d+)(?:,(\\w+))?>";
        Pattern pattern = Pattern.compile(regex);
        while (true) {
            String input = sc.nextLine().trim(); // 去除输入行的首尾空格
            if ("end".equalsIgnoreCase(input)) {
                break;
            }
            Matcher matcher = pattern.matcher(input);
            if (matcher.matches()) {
                String direction = matcher.group(2);
                if (direction == null) { // 电梯内乘客的请求
                    floorNum = Integer.parseInt(matcher.group(1));
                    queue.addInsideRequest(floorNum, lift);
                } else {
                    floorNum = Integer.parseInt(matcher.group(1));
                    queue.addOutsideRequest(floorNum, direction, lift);
                }
            }
        }
        controller.startMoving();
        sc.close();
    }
}

第二次程序:

点击查看代码

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Lift {
    private int minFloor;
    private int maxFloor;
    private int currentFloor;
    private String direction;      // 表示方向
    private String status;        // 表示电梯当前的运动状态

    public Lift(int minFloor, int maxFloor) {
        this.minFloor = minFloor;
        this.maxFloor = maxFloor;
        this.direction = "still";
        this.status = "stop";
        this.currentFloor = minFloor;
    }

    public int getCurrentFloor() {
        return currentFloor;
    }

    public void setCurrentFloor(int currentFloor) {
        this.currentFloor = currentFloor;
    }

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public int getMaxFloor() {
        return maxFloor;
    }

    public int getMinFloor() {
        return minFloor;
    }

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

    public boolean checkFloorNum(int floorNum) {
        return floorNum >= minFloor && floorNum <= maxFloor;
    }
}

class RequestQueue {
    private Deque<Integer> insideRequests;    // 储存电梯内乘客要到达的楼层
    private Deque<Integer> outsideRequests;    // 储存电梯外乘客所在楼层
    private Deque<String> outsideRequestsDirection;    // 储存电梯外乘客要前往的方向

    public RequestQueue() {
        this.insideRequests = new LinkedList<>();
        this.outsideRequests = new LinkedList<>();
        this.outsideRequestsDirection = new LinkedList<>();
    }

    public Deque<Integer> getInsideRequests() {
        return insideRequests;
    }

    public void setInsideRequests(Deque<Integer> insideRequests) {
        this.insideRequests = insideRequests;
    }

    public Deque<Integer> getOutsideRequests() {
        return outsideRequests;
    }

    public void setOutsideRequests(Deque<Integer> outsideRequests) {
        this.outsideRequests = outsideRequests;
    }

    public Deque<String> getOutsideRequestsDirection() {
        return outsideRequestsDirection;
    }

    public void setOutsideRequestsDirection(Deque<String> outsideRequestsDirection) {
        this.outsideRequestsDirection = outsideRequestsDirection;
    }

    // 添加内部乘客的请求
    public void addInsideRequest(int floorNum, Lift lift) {
        if (lift.checkFloorNum(floorNum)) {
            if (!insideRequests.isEmpty() && insideRequests.peekLast() == floorNum) {
            } else {
                insideRequests.add(floorNum);
            }
        }
    }

    // 添加外部乘客的请求
    public void addOutsideRequest(int floorNum, String direction, Lift lift) {
        if (lift.checkFloorNum(floorNum)) {
            if (!outsideRequests.isEmpty() && outsideRequests.peekLast() == floorNum && outsideRequestsDirection.peekLast().equals(direction)) {
            } else {
                outsideRequests.add(floorNum);
                outsideRequestsDirection.add(direction);
            }
        }
    }
}

class Controller {
    private Lift lift;
    private RequestQueue queue;

    public Controller(Lift lift, RequestQueue queue) {
        this.lift = lift;
        this.queue = queue;
    }

    public Lift getLift() {
        return lift;
    }

    public void setLift(Lift lift) {
        this.lift = lift;
    }

    public RequestQueue getQueue() {
        return queue;
    }

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

    public void startMoving() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        if (!insideRequests.isEmpty() || !outsideRequests.isEmpty()) {
            lift.setDirection("UP");
            lift.setStatus("moving");
            System.out.println("Current Floor: " + lift.getCurrentFloor() + " Direction: " + lift.getDirection());
            move();
        }
    }

    private void determineDirection() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        int currentFloor = lift.getCurrentFloor();
        String direction = lift.getDirection();
        //两个队列均不为空
        if (!insideRequests.isEmpty() && !outsideRequests.isEmpty())
        {
            if (insideRequests.peek() < currentFloor && outsideRequests.peek() < currentFloor)
                direction = "DOWN";
            else if (insideRequests.peek() > currentFloor && outsideRequests.peek() > currentFloor)
                direction = "UP";
        }
        else if (!insideRequests.isEmpty())//内部请求不为空,外部请求为空
        {
            if (insideRequests.peek() > currentFloor)
                direction = "UP";
            else if (insideRequests.peek() < currentFloor)
                direction = "DOWN";
        }
        else if (!outsideRequests.isEmpty())//外部请求不为空,内部请求为空
        {
            if (outsideRequests.peek() > currentFloor)
                direction = "UP";
            else if (outsideRequests.peek() < currentFloor)
                direction = "DOWN";
            else
            {
                if (!outsideRequests.isEmpty() && outsideRequests.peek() == currentFloor
                        && !outsideRequestsDirection.peek().equals(lift.getDirection()))
                {
                        if (outsideRequests.peek() > currentFloor)
                            direction = "UP";
                        else if (outsideRequests.peek() < currentFloor)
                            direction = "DOWN";
                }
            }
        }
        else
            direction = "still";
        lift.setDirection(direction);
    }

    public void move() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        int maxFloor = lift.getMaxFloor();
        int minFloor = lift.getMinFloor();
        while (!insideRequests.isEmpty() || !outsideRequests.isEmpty()) {
            String direction = lift.getDirection();
            int currentFloor = lift.getCurrentFloor();
            if (direction.equals("UP")) {
                while (currentFloor < maxFloor && direction.equals("UP")) {
                    currentFloor++;
                    lift.setCurrentFloor(currentFloor);
                    System.out.println("Current Floor: " + currentFloor + " Direction: UP");
                    if (ifStop(currentFloor)) {
                        stopHandle(currentFloor);
                    }
                    direction = lift.getDirection();
                }
            } else if (direction.equals("DOWN")) {
                while (currentFloor > minFloor && direction.equals("DOWN")) {
                    currentFloor--;
                    lift.setCurrentFloor(currentFloor);
                    System.out.println("Current Floor: " + currentFloor + " Direction: DOWN");
                    if (ifStop(currentFloor)) {
                        stopHandle(currentFloor);
                    }
                    direction = lift.getDirection();
                }
            }
            determineDirection();
        }
        lift.setStatus("stop");
        lift.setDirection("still");
    }

    public boolean ifStop(int floorNum) {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        String direction = lift.getDirection();

        Integer insidePeek = insideRequests.isEmpty() ? null : insideRequests.peek();
        Integer outsidePeek = outsideRequests.isEmpty() ? null : outsideRequests.peek();

        if (insidePeek != null && insidePeek == floorNum) {
            return true;
        }

        if (outsidePeek != null && !outsideRequestsDirection.isEmpty()
                && outsidePeek == floorNum
                && outsideRequestsDirection.peek().equals(direction)) {
            return true;
        }

        if (insidePeek == null && outsidePeek != null && outsidePeek == floorNum) {
            return true;
        }

        if (insidePeek != null && outsidePeek != null && outsidePeek == floorNum) {
            if (direction.equals("UP") && insidePeek < floorNum) {
                lift.setDirection(outsideRequestsDirection.peek());
                return true;
            } else if (direction.equals("DOWN") && insidePeek > floorNum) {
                lift.setDirection(outsideRequestsDirection.peek());
                return true;
            }
        }
        return false;
    }

    public void stopHandle(int floorNum) {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        lift.setStatus("stop");
        System.out.println("Open Door # Floor " + floorNum);
        // 移除当前楼层的内部请求
        if (!insideRequests.isEmpty() && insideRequests.peek() == floorNum) {
            insideRequests.remove();
        }
        // 移除当前楼层的外部请求
        if (!outsideRequests.isEmpty() && outsideRequests.peek() == floorNum) {
            outsideRequests.remove();
            outsideRequestsDirection.remove();
        }
        System.out.println("Close Door");
        determineDirection();
        lift.setStatus("moving");
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int minFloor = sc.nextInt();
        int maxFloor = sc.nextInt();
        int floorNum;
        sc.nextLine();
        Lift lift = new Lift(minFloor, maxFloor);
        RequestQueue queue = new RequestQueue();
        Controller controller = new Controller(lift, queue);
        // 正则表达式,匹配 <数字> 或 <数字,字母> 格式
        String regex = "<(\\d+)(?:,(\\w+))?>";
        Pattern pattern = Pattern.compile(regex);
        while (true) {
            String input = sc.nextLine().trim(); // 去除输入行的首尾空格
            if ("end".equalsIgnoreCase(input)) {
                break;
            }
            Matcher matcher = pattern.matcher(input);
            if (matcher.matches()) {
                String direction = matcher.group(2);
                if (direction == null) { // 电梯内乘客的请求
                    floorNum = Integer.parseInt(matcher.group(1));
                    queue.addInsideRequest(floorNum, lift);
                } else {
                    floorNum = Integer.parseInt(matcher.group(1));
                    queue.addOutsideRequest(floorNum, direction, lift);
                }
            }
        }
        controller.startMoving();
        sc.close();
    }
}

第三次程序:

点击查看代码

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Lift {
    private int minFloor;
    private int maxFloor;
    private int currentFloor;
    private String direction;      // 表示方向
    private String status;        // 表示电梯当前的运动状态
    private String where;

    public Lift(int minFloor, int maxFloor) {
        this.minFloor = minFloor;
        this.maxFloor = maxFloor;
        this.direction = "still";
        this.status = "stop";
        this.currentFloor = minFloor;
    }

    public int getCurrentFloor() {
        return currentFloor;
    }

    public void setCurrentFloor(int currentFloor) {
        this.currentFloor = currentFloor;
    }

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public int getMaxFloor() {
        return maxFloor;
    }

    public int getMinFloor() {
        return minFloor;
    }

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

    public boolean checkFloorNum(int floorNum) {
        return floorNum >= minFloor && floorNum <= maxFloor;
    }
    public String getWhere() {
        return where;
    }
    public void setWhere(String where) {
        this.where = where;
    }
}

class RequestQueue {
    private Deque<Integer> insideRequests;    // 储存电梯内乘客要到达的楼层
    private Deque<Integer> outsideRequests;    // 储存电梯外乘客所在楼层
    private Deque<String> outsideRequestsDirection;    // 储存电梯外乘客要前往的方向

    public RequestQueue() {
        this.insideRequests = new LinkedList<>();
        this.outsideRequests = new LinkedList<>();
        this.outsideRequestsDirection = new LinkedList<>();
    }

    public Deque<Integer> getInsideRequests() {
        return insideRequests;
    }

    public void setInsideRequests(Deque<Integer> insideRequests) {
        this.insideRequests = insideRequests;
    }

    public Deque<Integer> getOutsideRequests() {
        return outsideRequests;
    }

    public void setOutsideRequests(Deque<Integer> outsideRequests) {
        this.outsideRequests = outsideRequests;
    }

    public Deque<String> getOutsideRequestsDirection() {
        return outsideRequestsDirection;
    }

    public void setOutsideRequestsDirection(Deque<String> outsideRequestsDirection) {
        this.outsideRequestsDirection = outsideRequestsDirection;
    }

    // 添加内部乘客的请求
    public void addInsideRequest(int floorNum, Lift lift) {
        if (lift.checkFloorNum(floorNum)) {
            if (!insideRequests.isEmpty() && insideRequests.peekLast() == floorNum) {
            } else {
                insideRequests.add(floorNum);
            }
        }
    }

    // 添加外部乘客的请求
    public void addOutsideRequest(int floorNum, String direction, Lift lift) {
        if (lift.checkFloorNum(floorNum)) {
            if (!outsideRequests.isEmpty() && outsideRequests.peekLast() == floorNum && outsideRequestsDirection.peekLast().equals(direction)) {
            } else {
                outsideRequests.add(floorNum);
                outsideRequestsDirection.add(direction);
            }
        }
    }
}

class Controller {
    private Lift lift;
    private RequestQueue queue;

    public Controller(Lift lift, RequestQueue queue) {
        this.lift = lift;
        this.queue = queue;
    }

    public Lift getLift() {
        return lift;
    }

    public void setLift(Lift lift) {
        this.lift = lift;
    }

    public RequestQueue getQueue() {
        return queue;
    }

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

    public void startMoving() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        if (!insideRequests.isEmpty() || !outsideRequests.isEmpty()) {
            lift.setDirection("UP");
            lift.setStatus("moving");
            System.out.println("Current Floor: " + lift.getCurrentFloor() + " Direction: " + lift.getDirection());
            move();
        }
    }

    private void determineDirection() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        int currentFloor = lift.getCurrentFloor();
        String direction = lift.getDirection();
        //两个队列均不为空
        if (!insideRequests.isEmpty() && !outsideRequests.isEmpty())
        {
            if (insideRequests.peek() < currentFloor && outsideRequests.peek() < currentFloor)
                direction = "DOWN";
            else if (insideRequests.peek() > currentFloor && outsideRequests.peek() > currentFloor)
                direction = "UP";
        }
        else if (!insideRequests.isEmpty())//内部请求不为空,外部请求为空
        {
            if (insideRequests.peek() > currentFloor)
                direction = "UP";
            else if (insideRequests.peek() < currentFloor)
                direction = "DOWN";
        }
        else if (!outsideRequests.isEmpty())//外部请求不为空,内部请求为空
        {
            if (outsideRequests.peek() > currentFloor)
                direction = "UP";
            else if (outsideRequests.peek() < currentFloor)
                direction = "DOWN";
            else
            {
                if (!outsideRequests.isEmpty() && outsideRequests.peek() == currentFloor
                        && !outsideRequestsDirection.peek().equals(lift.getDirection()))
                {
                    if (outsideRequests.peek() > currentFloor)
                        direction = "UP";
                    else if (outsideRequests.peek() < currentFloor)
                        direction = "DOWN";
                }
            }
        }
        else
            direction = "still";
        lift.setDirection(direction);
    }

    public void move() {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        int maxFloor = lift.getMaxFloor();
        int minFloor = lift.getMinFloor();
        while (!insideRequests.isEmpty() || !outsideRequests.isEmpty()) {
            String direction = lift.getDirection();
            int currentFloor = lift.getCurrentFloor();
            if (direction.equals("UP")) {
                while (currentFloor < maxFloor && direction.equals("UP")) {
                    currentFloor++;
                    lift.setCurrentFloor(currentFloor);
                    System.out.println("Current Floor: " + currentFloor + " Direction: UP");
                    if (ifStop(currentFloor)) {
                        stopHandle(currentFloor);
                    }
                    direction = lift.getDirection();
                }
            } else if (direction.equals("DOWN")) {
                while (currentFloor > minFloor && direction.equals("DOWN")) {
                    currentFloor--;
                    lift.setCurrentFloor(currentFloor);
                    System.out.println("Current Floor: " + currentFloor + " Direction: DOWN");
                    if (ifStop(currentFloor)) {
                        stopHandle(currentFloor);
                    }
                    direction = lift.getDirection();
                }
            }
            determineDirection();
        }
        lift.setStatus("stop");
        lift.setDirection("still");
    }

    public boolean ifStop(int floorNum) {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        String direction = lift.getDirection();

        Integer insidePeek = insideRequests.isEmpty() ? null : insideRequests.peek();
        Integer outsidePeek = outsideRequests.isEmpty() ? null : outsideRequests.peek();

        if (insidePeek != null && insidePeek == floorNum) {
            lift.setWhere("inside");
            return true;
        }

        if (outsidePeek != null && !outsideRequestsDirection.isEmpty()
                && outsidePeek == floorNum
                && outsideRequestsDirection.peek().equals(direction)) {
            lift.setWhere("outside");
            return true;
        }

        if (insidePeek == null && outsidePeek != null && outsidePeek == floorNum) {
            lift.setWhere("outside");
            return true;
        }

        if (insidePeek != null && outsidePeek != null && outsidePeek == floorNum) {
            lift.setWhere("outside");
            if (direction.equals("UP") && insidePeek < floorNum) {
                lift.setDirection(outsideRequestsDirection.peek());
                return true;
            } else if (direction.equals("DOWN") && insidePeek > floorNum) {
                lift.setDirection(outsideRequestsDirection.peek());
                return true;
            }
        }
        return false;
    }

    public void stopHandle(int floorNum) {
        Deque<Integer> insideRequests = queue.getInsideRequests();
        Deque<Integer> outsideRequests = queue.getOutsideRequests();
        Deque<String> outsideRequestsDirection = queue.getOutsideRequestsDirection();
        lift.setStatus("stop");
        System.out.println("Open Door # Floor " + floorNum);
        // 移除当前楼层的内部请求
        if (!insideRequests.isEmpty() && insideRequests.peek() == floorNum && lift.getWhere().equals("inside")) {
            insideRequests.remove();
        }
        // 移除当前楼层的外部请求
        if (!outsideRequests.isEmpty() && outsideRequests.peek() == floorNum && lift.getWhere().equals("outside")) {
            outsideRequests.remove();
            outsideRequestsDirection.remove();
        }
        System.out.println("Close Door");
        determineDirection();
        lift.setStatus("moving");
    }
}

class Passenger{
    private int sourceFloor;
    private int destinationFloor;
    private String direction = "still";
    public Passenger(){
    }
    public Passenger(int sourceFloor, int destinationFloor) {
        this.sourceFloor =sourceFloor;
        this.destinationFloor =destinationFloor;
    }
    public int getDestinationFloor() {
        return destinationFloor;
    }
    public int getSourceFloor() {
        return sourceFloor;
    }
    public void setSourceFloor(int sourceFloor) {
        this.sourceFloor = sourceFloor;
    }
    public void setDestinationFloor(int destinationFloor) {
        this.destinationFloor = destinationFloor;
    }
    public String getDirection() {
        return direction;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int minFloor = sc.nextInt();
        int maxFloor = sc.nextInt();
        int floorNum, dirNum = 0;
        String direction = "still", direct;
        sc.nextLine();
        Lift lift = new Lift(minFloor, maxFloor);
        List<Integer> outsideDestinationFloors = new ArrayList<>();
        RequestQueue queue = new RequestQueue();
        Controller controller = new Controller(lift, queue);
        // 正则表达式,匹配 <数字> 或 <数字,数字> 格式
        String regex = "<(\\d+)(?:,(\\d+))?>";
        Pattern pattern = Pattern.compile(regex);
        while (true) {
            String input = sc.nextLine().trim(); // 去除输入行的首尾空格
            if ("end".equalsIgnoreCase(input)) {
                break;
            }
            Matcher matcher = pattern.matcher(input);
            if (matcher.matches()) {
                direct = matcher.group(2);
                floorNum = Integer.parseInt(matcher.group(1));
                if (direct == null) { // 电梯内乘客的请求
                    queue.addInsideRequest(floorNum, lift);
                }
                else {
                    dirNum = Integer.parseInt(direct);
                    if(floorNum > dirNum)
                        direction = "DOWN";
                    else if(floorNum < dirNum)
                        direction = "UP";
                    else
                        direction = "still";
                    queue.addOutsideRequest(floorNum, direction, lift);
                    outsideDestinationFloors.add(dirNum);
                }
            }
        }
        for(int i = 0; i < outsideDestinationFloors.size(); i++){
            queue.addInsideRequest(outsideDestinationFloors.get(i), lift);
        }
        controller.startMoving();
        sc.close();
    }
}

五、代码分析


图中显示的信息有:
代码行数为 373 行。
语句数量为 237 条 。
分支语句(如 if 、switch 等)占比为 18.1% ,说明代码中条件判断逻辑占一定比例。
方法调用语句数量为 119 条 。
注释行占比 3.5% ,注释较少,不利于代码理解和维护。
定义的类数量为 5 个 。
平均每个类的方法数为 7.60 个 。
平均每个方法的语句数为 4.37 条 。
最大复杂度为 20 ,说明代码中存在复杂度较高的方法,可能较难理解和维护。


% Comments:注释行占比 3.5% ,处于较低水平。
Avg Complexity:平均复杂度,反映代码整体的复杂程度。
Avg Depth:平均方法深度,体现方法内部嵌套结构的平均层数。
Max Depth:最大方法深度,即方法中最深的嵌套层数。
Max Complexity:最大复杂度,与第一张图对应。
Methods/Class:平均每个类的方法数。
Avg Stmts/Method:平均每个方法的语句数。
Block Histogram(柱状图):展示语句数量与代码深度(嵌套层数)的关系。从图中可以看到,深度为 1 的语句数量最多,随着深度增加,语句数量逐渐减少,但深度为 2、3 等仍有不少语句,说明代码中存在一定的嵌套结构。

从圈复杂度的角度分析:
圈复杂度用于衡量代码中独立路径的数量,通常反映代码的复杂程度。此代码里,determineDirection、move 和 ifStop 方法的圈复杂度较高。
determineDirection 方法:该方法包含多个 if-else 分支,依据不同请求队列的状态与当前楼层确定电梯方向,逻辑复杂。
move 方法:使用嵌套的 while 循环,依据电梯方向和楼层范围移动电梯,同时处理停止逻辑,增加了复杂度。
ifStop 方法:存在多个 if 条件判断,用于判定电梯是否在当前楼层停止,逻辑分支多。
从方法深度的角度分析:
determineDirection方法存在多层嵌套的 if-else 语句,最深嵌套达到 5 层,这使得代码逻辑复杂,难以理解和维护。move方法存在嵌套的 while 循环和 if-else 语句,最深嵌套达到 3 层,增加了代码的复杂度。
从代码逻辑清晰度的角度分析:
部分方法逻辑复杂,如determineDirection、move 和 ifStop 方法,嵌套的 if-else 语句和循环较多,难以理解和维护。
从复用性的角度分析:
优点就是按照要求将代码将不同功能封装到不同类和方法中,有一定复用性,例如 RequestQueue 类可在其他电梯模拟系统中复用。但是不足之处也很明显,部分方法与当前电梯模拟系统耦合度高,复用性受限。例如 determineDirection 方法的逻辑与当前请求队列和电梯状态紧密相关,难以在其他场景复用。

后续改进:

  1. 降低圈复杂度
    把复杂的 if-else 逻辑拆分成多个小方法,提高代码可读性和可维护性。
    减少嵌套循环,避免逻辑过于复杂。
  2. 提高代码逻辑清晰度
    采用更具描述性的变量名和方法名,增强代码可读性。
    添加注释,解释关键逻辑和方法的作用。
  3. 增强复用性
    降低方法与特定系统的耦合度,使方法更通用。

六、 总结与反思
这次迭代的程序让我学会了很多:利用正则表达式,类的设计与封装,锻炼了逻辑思维能力,还极大地磨练了我的意志。说实话第一次写电梯程序,我写了不下10个小时,中途很多次我都想过放弃,最后还是凭借意志力坚持下来了。而且此次的任务还提升了我优化程序的能力,我在一次次的修改优化迭代中,加深了对于程序设计的理解,也深刻的意识到了代码复用性的重要性。同时这次的迭代任务也让我意识到自身的很多问题。例如在处理较为复杂的问题是逻辑思路不够清晰,这需要首先充分理解需求,拥有一个大局观,还可以借助思维导图或表格等方式来帮助自己理清思路。面向对象程序设计的思维还不足,在对于类的封装是遇到了一些问题,这还需要在日后的练习中不断地进行训练。

posted @ 2025-04-17 18:34  南航码农  阅读(48)  评论(0)    收藏  举报