Jian-clever

导航

 

一.前言

电梯问题是我学java以来的第一个大型程序,并且进行了两次迭代,每次迭代都会在原有的基础上增加和删除功能,对于我来说是都是不小的挑战。经过这三次迭代作业让,我理解了Java在写大型程序时独特的优势,并且切身体会到了封装性原则以及面向对象原则有多么重要。俗话说磨刀不误砍柴工,我学得的一个重要经验便是,在写偏大型程序之前,一定要设计好代码的结构以及类与类之间的关系,思考代码需要有哪些功能,这些功能交给哪些类,有没有哪些功能可以优化。
三次作业所学
1.熟练设计多个类的程序
2.初步理解了java设计类时各种原则的重要性
3.学会考虑代码复用性
4.熟练的使用Idea中的各种调试方法

二.作业设计与分析

第一次电梯迭代

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

输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door

在这里强调一下电梯的运行规则:
一.首先按输入顺序把用户的请求分为内请求和外请求两个队列

二然后从两个队列的头部元素中选择一个作为电梯下一个目标楼层
三判断下一目标楼层
1.判断是否需要改变当前运行方向(不需要改变方向的请求优先)
1.内请求需要改变方向,外请求不需要改变方向-->选择外请求

2.外请求需要改变方向,内请求不需要改变方向-->选择内请求

2.如果内外请求都需要改变,判断外请求的方向与运行方向是否一致
1.外请求方向和运行方向一致-->选择外请求

 2.外请求方向和运行方向不一致
      1.内请求距离当前楼层更近-->选择内请求


2.外请求距离当前楼层更近-->选择外请求

源代码

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

// 方向枚举
enum Direction {
UP, DOWN
}

class Elevator
{
private int minFloor=1;
private int maxFloor=0;
private int currentFloor;
private int directionValue = 1;
private Queue internalRequests = new LinkedList<>();
private Queue externalRequests = new LinkedList<>();

public Elevator(int minFloor, int maxFloor)
{
    this.minFloor = minFloor;
    this.maxFloor = maxFloor;
    this.currentFloor = minFloor;
    this.internalRequests = new LinkedList<>();
    this.externalRequests = new LinkedList<>();

}

static class ExternalRequest
{
    int floor;
    Direction direction;

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

}

public void addExternalRequest(int floor, Direction direction)
{
    if (floor >= minFloor && floor <= maxFloor)
    {
        externalRequests.add(new ExternalRequest(floor, direction));
    }
}

// 添加内部请求
public void addInternalRequest(int floor)
{
    if (floor >= minFloor && floor <= maxFloor)
    {
        internalRequests.add(floor);
    }
}
public void processRequests()
{
    while (!internalRequests.isEmpty()||!externalRequests.isEmpty())/// //////////////////////////////////////////////////
    {
        int[] result = getTargetFloorAndDirection();
        int targetFloor = result[0];

        Direction targetDirection;
        if (result[1] == 1) {
            targetDirection = Direction.UP;
        } else {
            targetDirection = Direction.DOWN;
        }
        moveToFloor(targetFloor, targetDirection);
    }
}

private void moveToFloor(int targetFloor, Direction targetDirection) {
    if (targetFloor == currentFloor) {
        System.out.print(("\n"));
        System.out.printf("Current Floor: %d Direction: DOWN", currentFloor);
    } else if (targetFloor > currentFloor) {
        while (currentFloor < targetFloor) {
            currentFloor++;
            System.out.print(("\n"));
            System.out.printf("Current Floor: %d Direction: UP", currentFloor);
        }
    }
    if (targetFloor < currentFloor) {
        while (currentFloor > targetFloor) {
            currentFloor--;
            System.out.print("\n");
            System.out.printf("Current Floor: %d Direction: DOWN", currentFloor);
        }
    }
    System.out.print("\n");
    System.out.printf("Open Door # Floor %d", targetFloor);
    System.out.print("\n");
    System.out.print("Close Door");
}
private int[] getTargetFloorAndDirection()
{
    int  targetFloor = -1;;
    if(currentFloor==maxFloor)
    {
        directionValue = 0;
    }else if(currentFloor==minFloor)
    {
        directionValue=1;
    }

    Direction currentDirection;
    if (directionValue == 1) {
        currentDirection = Direction.UP;
    } else {
        currentDirection = Direction.DOWN;
    }

    ExternalRequest nextExternal;
    nextExternal = externalRequests.peek();
    Integer nextInternal;
    nextInternal = internalRequests.peek();

    if (externalRequests.isEmpty()||internalRequests.isEmpty())
    {
        if (!internalRequests.isEmpty())
        {
            targetFloor = nextInternal;

        } else if (!externalRequests.isEmpty() )
        {
            targetFloor = nextExternal.floor;

        }
    }else {
        if (currentDirection == Direction.UP)/// //////////////////////////////////////////////////////
        {
            if(nextExternal.floor==nextInternal)
            {
                targetFloor=nextInternal;
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else{
                    directionValue=0;
                }
            }else if ((nextInternal >currentFloor && nextExternal.floor<currentFloor))//3
            {
                targetFloor = nextInternal;
                directionValue = 1;//
            } else if ((nextExternal.floor>currentFloor && nextInternal <currentFloor)) //4
            {
                targetFloor = nextExternal.floor;
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else
                {
                    directionValue = 0;//
                }
            } else if ((nextExternal.floor >currentFloor && nextInternal > currentFloor))
            {
                if (nextExternal.direction == currentDirection)
                {
                    if (nextInternal < nextExternal.floor) {
                        targetFloor = nextInternal;
                        directionValue = 1;
                    }
                        targetFloor = nextExternal.floor;
                } else if (nextExternal.direction != currentDirection)//没问题
                {
                    targetFloor = nextInternal;
                    directionValue = 1;
                }

            } else if (  (nextExternal.floor < currentFloor && nextInternal <currentFloor))
            {
                if (nextExternal.direction == currentDirection) {
                    targetFloor = nextExternal.floor;
                    if(nextExternal.direction==Direction.UP)
                    {
                        directionValue=1;
                    }else
                    {
                        directionValue = 0;//
                    }
                } else if (nextExternal.direction != currentDirection) {
                    if (nextInternal > nextExternal.floor) {
                        targetFloor = nextInternal;
                        directionValue = 0;//
                    } else if (nextExternal.floor >nextInternal) {
                        targetFloor = nextExternal.floor;
                        if(nextExternal.direction==Direction.UP)
                        {
                            directionValue=1;
                        }else
                        {
                            directionValue = 0;//
                        }
                    }
                }
            }else if(nextExternal.floor==nextInternal)
            {
                targetFloor=nextInternal;
                internalRequests.poll();
                externalRequests.poll();
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else{
                    directionValue=0;
                }///////////////////////////
            }
        } else if (currentDirection == Direction.DOWN) ////////////////////////////////////////////////////////
        {
            if(nextExternal.floor==nextInternal)
            {
                targetFloor=nextInternal;
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else{
                    directionValue=0;
                }
            }else if ( (nextInternal > currentFloor && nextExternal.floor <currentFloor))//3
            {
                targetFloor = nextExternal.floor;//
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else
                {
                    directionValue = 0;//
                }
            } else if ( (nextExternal.floor > currentFloor && nextInternal <currentFloor)) //4
            {
                targetFloor = nextInternal;//
                directionValue = 0;

            } else if ( (nextExternal.floor > currentFloor && nextInternal >currentFloor))
            {
                if (nextExternal.direction == currentDirection) {
                    if (nextInternal < nextExternal.floor)
                    {
                        targetFloor = nextInternal;//
                        if(nextExternal.direction==Direction.UP)
                        {
                            directionValue=1;
                        }else
                        {
                            directionValue = 0;//
                        }

                    } else if (nextExternal.floor <nextInternal) {
                        targetFloor = nextExternal.floor;//
                        directionValue = 1;

                    }
                } else if (nextExternal.direction != currentDirection) {
                    targetFloor = nextExternal.floor;//
                    if(nextExternal.direction==Direction.UP)
                    {
                        directionValue=1;
                    }else
                    {
                        directionValue = 0;//
                    }
                }

            } else if ((nextExternal.floor < currentFloor && nextInternal < currentFloor))
            {
                // 处理向下的内部请求
                if (nextExternal.direction != currentDirection) {
                    targetFloor = nextInternal;//
                    directionValue = 0;//

                } else if (nextExternal.direction == currentDirection) {
                    if (nextInternal > nextExternal.floor) {
                        targetFloor = nextInternal;
                        directionValue = 0;//


                    } else if (nextExternal.floor > nextInternal) {
                        targetFloor = nextExternal.floor;
                        if(nextExternal.direction==Direction.UP)
                        {
                            directionValue=1;
                        }else
                        {
                            directionValue = 0;//
                        }
                    }
                }
            }


        }
    }

    if(!internalRequests.isEmpty()&&!externalRequests.isEmpty())
    {

        int a=nextInternal;
        int b=nextExternal.floor;


        if (a == b) {
            internalRequests.poll();
            externalRequests.poll();
        } else {
            if (targetFloor ==a) {
                internalRequests.poll();

            } else if (targetFloor == b) {
                externalRequests.poll();

            }
        }
    }else{
        if(!internalRequests.isEmpty())
        {
            internalRequests.poll();
        }else if(!externalRequests.isEmpty())
        {
            externalRequests.poll();
        }
    }
    return new int[]{targetFloor, directionValue};
}

}

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

public RequestQueue() {
}

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

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

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

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

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

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

}

class Controller {
private Elevator elevator;
private RequestQueue queue;

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() {
    elevator.processRequests();
}

}

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 list = new ArrayList<>();

    data = input.nextLine();
    while (!data.equalsIgnoreCase("end")) {
        list.add(data);
        data = input.nextLine();
    }

    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 = Direction.valueOf(parts[1].trim().toUpperCase());
            elevator.addExternalRequest(floor, direction);
        } else {
            if (!request.matches("<\\d+>")) {
                System.out.println("Wrong Format");
            }
            floor = Integer.parseInt(request.replaceAll("[<>]", ""));
            elevator.addInternalRequest(floor);
        }
    }
    System.out.print("Current Floor: 1 Direction: UP");
    elevator.processRequests();

    input.close();
}

}

设计

1.设计思路

主体功能就是
1.读取请求,并且分为两个队列
2.判断哪个队列是下一目标楼层
3.打印电梯运行过程

首先定义Elevator类作为核心,封装电梯的关键属性与行为。
属性:minFloor(最低楼层)、maxFloor(最高楼层)、currentFloor(当前楼层)、directionValue(运行方向标识)等,用于描述电梯的状态;
行为:addExternalRequest(添加外部请求)、addInternalRequest(添加内部请求)、processRequests(处理请求)等方法;
processRequests:作为核心处理逻辑,通过循环不断检查内部和外部请求队列
moveToFloor:获得现在楼层和下一请求后输出电梯运行过程。
getTargetFloorAndDirection:是最重要的一个类,也是最复杂的一个类,需要在两个请求中判断下一个请求。
RequestQueue:负责管理电梯的请求队列,包括内部请求队列internalRequests和外部请求队列externalRequests,提供添加请求的方法,确保请求能够有序存储。

getTargetFloorAndDirection:在内请求和外请求之中判断哪一个为下一个请求,是代码行数最多的类,需要单独讲。由于我一开始认为电梯的问题太过于复杂,所以我使用了大量的if-else语句,穷举了所有可能。getTargetFloorAndDirection类先会判断当前电梯的状态,分为向上和向下两种情况,这样考虑时会更加方便,也更加有条理性。
moveToFloor方法根据目标楼层和运行方向,控制电梯的移动,并在到达目标楼层时输出相应的提示信息,如当前楼层、运行方向、开门和关门等。

2.类图

3.代码规模


代码规模:行数达 448 行,包含 263 条语句。

4.复杂度分析


分支语句占比:分支语句占比 31.2% ,表明代码中存在大量条件判断逻辑。过多的分支会使代码逻辑复杂。
方法调用情况:有 67 条方法调用语句,反映出代码通过方法调用来组织功能,实现模块化。
注释比例:仅有 6.9% 的行包含注释,注释过少不利于他人。
最大块深度与平均块深度:最大块深度为 8 ,平均块深度为 3.18 。意味着代码逻辑嵌套很深,使代码执行逻辑难以梳理,维护时容易出错。
平均复杂度:平均复杂度为 5.10 ,说明代码整体的复杂度处于一定高度,各部分代码在逻辑、结构等方面都存在相当程度的复杂性。

第二次电梯迭代

电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>

源代码

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

// 方向枚举
enum Direction {
UP, DOWN
}

class Elevator
{
private int minFloor=1;
private int maxFloor=0;
private int currentFloor;
private int directionValue = 1;
private Queue internalRequests = new LinkedList<>();
private Queue externalRequests = new LinkedList<>();

public Elevator(int minFloor, int maxFloor)
{
    this.minFloor = minFloor;
    this.maxFloor = maxFloor;
    this.currentFloor = minFloor;
    this.internalRequests = new LinkedList<>();
    this.externalRequests = new LinkedList<>();

}

static class ExternalRequest
{
    int floor;
    Direction direction;

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

}

public void addExternalRequest(int floor, Direction direction)
{
    if (floor >= minFloor && floor <= maxFloor)
    {
        externalRequests.add(new ExternalRequest(floor, direction));
    }
}

// 添加内部请求
public void addInternalRequest(int floor)
{
    if (floor >= minFloor && floor <= maxFloor)
    {
        internalRequests.add(floor);
    }
}
public void processRequests()
{
    while (!internalRequests.isEmpty()||!externalRequests.isEmpty())/// //////////////////////////////////////////////////
    {
        int[] result = getTargetFloorAndDirection();
        int targetFloor = result[0];

        Direction targetDirection;
        if (result[1] == 1) {
            targetDirection = Direction.UP;
        } else {
            targetDirection = Direction.DOWN;
        }
        moveToFloor(targetFloor, targetDirection);
    }
}

private void moveToFloor(int targetFloor, Direction targetDirection) {
    if (targetFloor == currentFloor) {
        System.out.print(("\n"));
        System.out.printf("Current Floor: %d Direction: DOWN", currentFloor);
    } else if (targetFloor > currentFloor) {
        while (currentFloor < targetFloor) {
            currentFloor++;
            System.out.print(("\n"));
            System.out.printf("Current Floor: %d Direction: UP", currentFloor);
        }
    }
    if (targetFloor < currentFloor) {
        while (currentFloor > targetFloor) {
            currentFloor--;
            System.out.print("\n");
            System.out.printf("Current Floor: %d Direction: DOWN", currentFloor);
        }
    }
    System.out.print("\n");
    System.out.printf("Open Door # Floor %d", targetFloor);
    System.out.print("\n");
    System.out.print("Close Door");
}
private int[] getTargetFloorAndDirection()
{
    int  targetFloor = -1;;
    if(currentFloor==maxFloor)
    {
        directionValue = 0;
    }else if(currentFloor==minFloor)
    {
        directionValue=1;
    }

    Direction currentDirection;
    if (directionValue == 1) {
        currentDirection = Direction.UP;
    } else {
        currentDirection = Direction.DOWN;
    }

    ExternalRequest nextExternal;
    nextExternal = externalRequests.peek();
    Integer nextInternal;
    nextInternal = internalRequests.peek();

    if (externalRequests.isEmpty()||internalRequests.isEmpty())
    {
        if (!internalRequests.isEmpty())
        {
            targetFloor = nextInternal;

        } else if (!externalRequests.isEmpty() )
        {
            targetFloor = nextExternal.floor;

        }
    }else {
        if (currentDirection == Direction.UP)/// //////////////////////////////////////////////////////
        {
            if(nextExternal.floor==nextInternal)
            {
                targetFloor=nextInternal;
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else{
                    directionValue=0;
                }
            }else if ((nextInternal >currentFloor && nextExternal.floor<currentFloor))//3
            {
                targetFloor = nextInternal;
                directionValue = 1;//
            } else if ((nextExternal.floor>currentFloor && nextInternal <currentFloor)) //4
            {
                targetFloor = nextExternal.floor;
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else
                {
                    directionValue = 0;//
                }
            } else if ((nextExternal.floor >currentFloor && nextInternal > currentFloor))
            {
                if (nextExternal.direction == currentDirection)
                {
                    if (nextInternal < nextExternal.floor) {
                        targetFloor = nextInternal;
                        directionValue = 1;
                    } else if (nextExternal.floor < nextInternal) {
                        targetFloor = nextExternal.floor;
                        if(nextExternal.direction==Direction.UP)/// //////没有问题
                        {
                            directionValue=1;
                        }else
                        {
                            directionValue = 0;//
                        }
                    }
                } else if (nextExternal.direction != currentDirection)//没问题
                {
                    targetFloor = nextInternal;
                    directionValue = 1;
                }

            } else if (  (nextExternal.floor < currentFloor && nextInternal <currentFloor))
            {
                if (nextExternal.direction == currentDirection) {
                    targetFloor = nextExternal.floor;
                    if(nextExternal.direction==Direction.UP)
                    {
                        directionValue=1;
                    }else
                    {
                        directionValue = 0;//
                    }
                } else if (nextExternal.direction != currentDirection) {
                    if (nextInternal > nextExternal.floor) {
                        targetFloor = nextInternal;
                        directionValue = 0;//
                    } else if (nextExternal.floor >nextInternal) {
                        targetFloor = nextExternal.floor;
                        if(nextExternal.direction==Direction.UP)
                        {
                            directionValue=1;
                        }else
                        {
                            directionValue = 0;//
                        }
                    }
                }
            }else if(nextExternal.floor==nextInternal)
            {
                targetFloor=nextInternal;
                internalRequests.poll();
                externalRequests.poll();
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else{
                    directionValue=0;
                }///////////////////////////
            }
        } else if (currentDirection == Direction.DOWN) ////////////////////////////////////////////////////////
        {
            if(nextExternal.floor==nextInternal)
            {
                targetFloor=nextInternal;
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else{
                    directionValue=0;
                }
            }else if ( (nextInternal > currentFloor && nextExternal.floor <currentFloor))//3
            {
                targetFloor = nextExternal.floor;//
                if(nextExternal.direction==Direction.UP)
                {
                    directionValue=1;
                }else
                {
                    directionValue = 0;//
                }
            } else if ( (nextExternal.floor > currentFloor && nextInternal <currentFloor)) //4
            {
                targetFloor = nextInternal;//
                directionValue = 0;

            } else if ( (nextExternal.floor > currentFloor && nextInternal >currentFloor))
            {
                if (nextExternal.direction == currentDirection) {
                    if (nextInternal < nextExternal.floor)
                    {
                        targetFloor = nextInternal;//
                        if(nextExternal.direction==Direction.UP)
                        {
                            directionValue=1;
                        }else
                        {
                            directionValue = 0;//
                        }

                    } else if (nextExternal.floor <nextInternal) {
                        targetFloor = nextExternal.floor;//
                        directionValue = 1;

                    }
                } else if (nextExternal.direction != currentDirection) {
                    targetFloor = nextExternal.floor;//
                    if(nextExternal.direction==Direction.UP)
                    {
                        directionValue=1;
                    }else
                    {
                        directionValue = 0;//
                    }
                }

            } else if ((nextExternal.floor < currentFloor && nextInternal < currentFloor))
            {
                // 处理向下的内部请求
                if (nextExternal.direction != currentDirection) {
                    targetFloor = nextInternal;//
                    directionValue = 0;//

                } else if (nextExternal.direction == currentDirection) {
                    if (nextInternal > nextExternal.floor) {
                        targetFloor = nextInternal;
                        directionValue = 0;//


                    } else if (nextExternal.floor > nextInternal) {
                        targetFloor = nextExternal.floor;
                        if(nextExternal.direction==Direction.UP)
                        {
                            directionValue=1;
                        }else
                        {
                            directionValue = 0;//
                        }
                    }
                }
            }


        }
    }

    if(!internalRequests.isEmpty()&&!externalRequests.isEmpty())
    {

        int a=nextInternal;
        int b=nextExternal.floor;


        if (a == b) {
            internalRequests.poll();
            externalRequests.poll();
        } else {
            if (targetFloor ==a) {
                internalRequests.poll();

            } else if (targetFloor == b) {
                externalRequests.poll();

            }
        }
    }else{
        if(!internalRequests.isEmpty())
        {
            internalRequests.poll();
        }else if(!externalRequests.isEmpty())
        {
            externalRequests.poll();
        }
    }
    return new int[]{targetFloor, directionValue};
}

}

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

public RequestQueue() {
}

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

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

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

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

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

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

}

class Controller {
private Elevator elevator;
private RequestQueue queue;

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() {
    elevator.processRequests();
}

}

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 list = new ArrayList<>();

    data = input.nextLine();
    while (!data.equalsIgnoreCase("end")) {
        list.add(data);
        data = input.nextLine();
    }

    minFloor = Integer.parseInt(list.get(0));
    maxFloor = Integer.parseInt(list.get(1));

    Elevator elevator = new Elevator(minFloor, maxFloor);

    // 用于记录上一个有效请求
    String lastValidRequest = "";
    for (int i = 2; i < list.size(); i++) {
        request = list.get(i);
        if (request.contains(",")) {
            if (request.matches("<\\d+,\\s*(UP|DOWN)>")) {
                String[] parts = request.replaceAll("[<>]", "").split(",");
                floor = Integer.parseInt(parts[0].trim());
                direction = Direction.valueOf(parts[1].trim().toUpperCase());
                if (floor >= minFloor && floor <= maxFloor) {
                    // 检查是否与上一个有效外部请求相同
                    if (!request.equals(lastValidRequest)) {
                        elevator.addExternalRequest(floor, direction);
                        lastValidRequest = request;
                    }
                }
            }
        } else {
            if (request.matches("<\\d+>")) {
                floor = Integer.parseInt(request.replaceAll("[<>]", ""));
                if (floor >= minFloor && floor <= maxFloor) {
                    // 检查是否与上一个有效内部请求相同
                    if (!request.equals(lastValidRequest)) {
                        elevator.addInternalRequest(floor);
                        lastValidRequest = request;
                    }
                }
            }
        }
    }
    System.out.print("Current Floor: 1 Direction: UP");
    elevator.processRequests();

    input.close();
}

}

设计

1.设计思路

题目集 6 在题目集 5 的基础上,要求程序能够过滤重复请求,符合现实中用户多次按按钮的情况。

Elevator类:在处理请求的核心逻辑上进行优化。
getTargetFloorAndDirection:由于新增了请求优先级、特殊请求类型等条件,需要在原有的逻辑判断基础上,增加更多的分支条件。
addExternalRequest和addInternalRequest:增加对重复请求的检查逻辑,避免无效请求的重复处理,提高程序效率。通过记录上一个处理的请求信息,在添加新请求时进行对比判断,只有不重复的请求才会被真正添加到队列中。
RequestQueue:在题目集 6 中,根据新的请求管理需求,对请求队列的存储结构或操作方式进行调整。例如,为了更好地支持优先级请求,将请求队列改为优先队列,使高优先级请求能够优先被处理;或者增加对请求状态的记录和管理,以便更准确地跟踪请求的处理情况。
Controller:新增加的类,使电梯协调功能增强,需要根据新的请求处理规则,合理调度Elevator类的操作。该类在一开始我并想到,后来题目做出要求后我发现这个类非常的科学,对迭代很有用。
Main类进一步强化输入数据的验证和预处理。除了基本的格式检查外,还需根据新的请求规则,对输入数据进行更严格的合法性验证。例如,对于特殊请求类型,检查输入是否符合规定的格式和条件;对于请求的楼层范围,进行更细致的边界检查,确保输入数据的准确性。

2.类图

3.代码规模

整体规模与结构
行数(Lines)与语句数(Statements):457 行代码,265 条语句。

4.复杂度分析

因为增加了controll类,代码复杂度有一定的降低。

类与接口数量(Classes and Interfaces):有 6 个,平均每个类 3.5 个方法(Methods per Class ),平均每个方法 9.62 条语句(Average Statements per Method ) 。
分支语句占比(Percent Branch Statements ):达 31.7% ,意味着代码中存在大量条件判断逻辑,会使代码逻辑复杂。
最大块深度(Maximum Block Depth )与平均块深度(Average Block Depth ):最大块深度为 8 ,平均块深度 3.19 。块深度反映控制结构(如 if - else、for、while 等)的嵌套层数,较大的块深度表明代码逻辑嵌套深,代码执行逻辑不易梳理,容易出现逻辑错误且难以排查。
最复杂方法(Name of Most Complex Method :Elevator.getTargetFloorAndDirection() 方法最为复杂,行数 98 行,复杂度 68 。
注释比例(Percent Lines with Comments ):仅 7.4% ,注释过少不利于理解代码逻辑和功能意图。
平均复杂度(Average Complexity ):为 5.29 ,表明代码整体复杂程度很高。

第三次电梯迭代

电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)

源代码

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

// 方向枚举
enum Direction {
UP, DOWN
}
class Elevator {
private int minFloor = 1;
private int maxFloor = 0;
private int currentFloor;
private int directionValue = 1;
private Queue internalRequests = new LinkedList<>();
private Queue externalRequests = new LinkedList<>();
public Elevator(int minFloor, int maxFloor) {
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.currentFloor = minFloor;
this.internalRequests = new LinkedList<>();
this.externalRequests = new LinkedList<>();
}
static class Passenger {
int sourceFloor;
int destinationFloor;
public Passenger(int sourceFloor, int destinationFloor)
{
this.sourceFloor = sourceFloor;
this.destinationFloor = destinationFloor;

    }
}
public void addExternalRequest(int sourceFloor, int destinationFloor) {
    if (sourceFloor >= minFloor && sourceFloor <= maxFloor && destinationFloor >= minFloor && destinationFloor <= maxFloor) {
        externalRequests.add(new Passenger(sourceFloor, destinationFloor));
    }
}
public void addInternalRequest(int floor) {
    if (floor >= minFloor && floor <= maxFloor) {
        internalRequests.add(floor);
    }
}
public void processRequests() {
    while (!internalRequests.isEmpty() || !externalRequests.isEmpty()) {
        int[] result = getTargetFloorAndDirection();
        int targetFloor = result[0];

        Direction targetDirection;
        if (result[1] == 1) {
            targetDirection = Direction.UP;
        } else {
            targetDirection = Direction.DOWN;
        }
        moveToFloor(targetFloor, targetDirection);
    }
}
private void moveToFloor(int targetFloor, Direction targetDirection) {
    if (targetFloor == currentFloor) {
        System.out.print(("\n"));
        System.out.printf("Current Floor: %d Direction: DOWN", currentFloor);
    } else if (targetFloor > currentFloor) {
        while (currentFloor < targetFloor) {
            currentFloor++;
            System.out.print(("\n"));
            System.out.printf("Current Floor: %d Direction: UP", currentFloor);
        }
    }
    if (targetFloor < currentFloor) {
        while (currentFloor > targetFloor) {
            currentFloor--;
            System.out.print("\n");
            System.out.printf("Current Floor: %d Direction: DOWN", currentFloor);
        }
    }
    System.out.print("\n");
    System.out.printf("Open Door # Floor %d", targetFloor);
    System.out.print("\n");
    System.out.print("Close Door");
    if (!externalRequests.isEmpty()) {
        Passenger passenger = externalRequests.peek();
    }
}
private int[] getTargetFloorAndDirection()
{
    int targetFloor = -1;
    if (currentFloor == maxFloor) {
        directionValue = 0;
    } else if (currentFloor == minFloor) {
        directionValue = 1;
    }
    Direction currentDirection;
    if (directionValue == 1) {
        currentDirection = Direction.UP;
    } else {
        currentDirection = Direction.DOWN;
    }
    Passenger nextExternal;
    nextExternal = externalRequests.peek();
    Integer nextInternal;
    nextInternal = internalRequests.peek();
    if (externalRequests.isEmpty() || internalRequests.isEmpty())
    {
    }else {
        if(nextInternal==nextExternal.sourceFloor) {
            targetFloor = nextInternal;
            if ((nextExternal.destinationFloor > nextExternal.sourceFloor) && currentDirection == Direction.UP) {

                directionValue = 1;
                internalRequests.add(nextExternal.destinationFloor);
                internalRequests.poll();
                externalRequests.poll();
            } else if (nextExternal.destinationFloor < nextExternal.sourceFloor && currentDirection == Direction.DOWN) {
                directionValue = 0;
                internalRequests.add(nextExternal.destinationFloor);
                internalRequests.poll();
                externalRequests.poll();
            } else {
                if (internalRequests.size() == 1) {
                    internalRequests.add(nextExternal.destinationFloor);
                    internalRequests.poll();
                    externalRequests.poll();
                } else {
                    if (nextInternal > currentFloor) {
                        directionValue = 1;
                    } else {
                        directionValue = 0;
                    }
                    internalRequests.poll();
                }
            }
                return new int[]{targetFloor, directionValue};
        }

        if(currentFloor==nextExternal.sourceFloor||currentFloor==nextInternal)
        {
            if(currentFloor==nextInternal)
            {
                targetFloor=nextExternal.sourceFloor;
                internalRequests.add(nextExternal.destinationFloor);
                externalRequests.poll();
                if(nextInternal>currentFloor)
                {
                    directionValue=1;
                }else{
                    directionValue=0;
                }

            }else
            {
                targetFloor=nextInternal;
                internalRequests.poll();
                if(nextExternal.sourceFloor>currentFloor)
                {
                    directionValue=1;
                }else{
                    directionValue=0;
                }
            }
            return new int[]{targetFloor, directionValue};
        }



        if(currentDirection == Direction.UP)
        {
            if ((nextInternal > currentFloor && nextExternal.sourceFloor < currentFloor)) {
                 targetFloor = nextInternal;
                directionValue = 1;

            } else if ((nextExternal.sourceFloor >currentFloor && nextInternal<currentFloor))
            {
                targetFloor = nextExternal.sourceFloor;
                if (nextExternal.destinationFloor>nextExternal.sourceFloor) {
                    directionValue = 1;
                } else {
                    directionValue = 0;
                }
            }else if ((nextExternal.sourceFloor >currentFloor&&nextInternal >currentFloor))//////////////////////
            {
                if (nextExternal.destinationFloor>nextExternal.sourceFloor)
                {
                    if (nextInternal < nextExternal.sourceFloor)
                    {
                        targetFloor = nextInternal;
                        directionValue = 1;
                    } else if (nextExternal.sourceFloor < nextInternal)//理解
                    {
                        targetFloor = nextExternal.sourceFloor;
                        directionValue = 1;
                    }
                }else if(nextExternal.destinationFloor<nextExternal.sourceFloor)
                {
                    directionValue = 1;
                    targetFloor = nextInternal;
                }
            } else if ((nextExternal.sourceFloor < currentFloor && nextInternal < currentFloor))
            {

                if (nextExternal.destinationFloor>nextExternal.sourceFloor)
                {
                    targetFloor= nextExternal.sourceFloor;
                    directionValue=1;
                } else if (nextExternal.destinationFloor<nextExternal.sourceFloor)
                {

                    if (nextInternal > nextExternal.sourceFloor) {
                        targetFloor = nextInternal;
                        directionValue = 0;
                    } else if (nextExternal.sourceFloor > nextInternal)
                    {
                        targetFloor = nextInternal;
                            directionValue = 0;
                    }
                }

            }
        } else if (currentDirection == Direction.DOWN) ///////////////////////////////
        {
            if ((nextInternal > currentFloor && nextExternal.sourceFloor < currentFloor))
            {
                targetFloor = nextExternal.sourceFloor;
                if (nextExternal.destinationFloor > nextExternal.sourceFloor) {
                    directionValue = 1;
                } else {
                    directionValue = 0;
                }
            } else if ((nextExternal.sourceFloor > currentFloor && nextInternal < currentFloor))
            {
                targetFloor = nextInternal;
                directionValue = 0;

            } else if ((nextExternal.sourceFloor > currentFloor && nextInternal > currentFloor))
            {
                if (nextExternal.destinationFloor>nextExternal.sourceFloor)
                {
                    if (nextInternal < nextExternal.sourceFloor) {
                        targetFloor = nextInternal;
                    } else if (nextExternal.sourceFloor < nextInternal) {
                        targetFloor = nextExternal.sourceFloor;
                        directionValue = 1;
                    }
                } else if (nextExternal.destinationFloor<nextExternal.sourceFloor)
                {
                    targetFloor = nextExternal.sourceFloor;
                    directionValue = 0;
                }
            } else if ((nextExternal.sourceFloor < currentFloor && nextInternal < currentFloor))
            {
                if (nextExternal.destinationFloor>nextExternal.sourceFloor) {
                    targetFloor = nextInternal;
                    directionValue = 0;

                } else if (nextExternal.destinationFloor<nextExternal.sourceFloor)
                {
                    if (nextInternal > nextExternal.sourceFloor) {
                        targetFloor = nextInternal;
                        directionValue = 0;
                    } else if (nextExternal.sourceFloor > nextInternal)
                    {
                        targetFloor = nextExternal.sourceFloor;
                        directionValue = 0;
                    }
                }
            }
        }

    }
    if (internalRequests.isEmpty()|| externalRequests.isEmpty())
    {
        if (!internalRequests.isEmpty())
        {
            targetFloor=nextInternal;

            if(nextInternal>currentFloor)
            {
                directionValue=1;
            }else{
                directionValue=0;
            }
            internalRequests.poll();
        } else if (!externalRequests.isEmpty())
        {
            if(nextExternal.sourceFloor>currentFloor)
            {
                directionValue=1;
            }else{
                directionValue=0;
            }

            targetFloor=nextExternal.sourceFloor;
            internalRequests.add(nextExternal.destinationFloor);
            externalRequests.poll();
        }
    } else
    {
        if (targetFloor == nextInternal)
        {
            internalRequests.poll();
        } else if (targetFloor == nextExternal.sourceFloor) {
            internalRequests.add(nextExternal.destinationFloor);
            externalRequests.poll();
        }
    }
    return new int[]{targetFloor, directionValue};
}

}

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

public RequestQueue() {
}
public void addInternalRequest(int floor) {
    internalRequests.add(floor);
}
public void addExternalRequest(int sourceFloor, int destinationFloor) {
    externalRequests.add(new Elevator.Passenger(sourceFloor, destinationFloor));
}

}

class Controller {
private Elevator elevator;
private RequestQueue queue;
public Controller(Elevator elevator, RequestQueue queue)
{
this.elevator = elevator;
this.queue = queue;
}
public void processRequests()
{
elevator.processRequests();
}
}

public class Main1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String data;
int sourceFloor = 0;
int destinationFloor = 0;
int minFloor, maxFloor;
String request = "";
ArrayList list = new ArrayList<>();
data = input.nextLine();
while (!data.equalsIgnoreCase("end")) {
list.add(data);
data = input.nextLine();
}
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);
String lastValidRequest = "";
for (int i = 2; i < list.size(); i++) {
request = list.get(i);
if (request.contains(",")) {
if (request.matches("<\d+,\s*\d+>")) {
String[] parts = request.replaceAll("[<>]", "").split(",");
sourceFloor = Integer.parseInt(parts[0].trim());
destinationFloor = Integer.parseInt(parts[1].trim());
if (sourceFloor >= minFloor && sourceFloor <= maxFloor && destinationFloor >= minFloor && destinationFloor <= maxFloor) {
if (!request.equals(lastValidRequest)) {
elevator.addExternalRequest(sourceFloor, destinationFloor);
queue.addExternalRequest(sourceFloor, destinationFloor);
lastValidRequest = request;
}
}
}
} else {
if (request.matches("<\d+>")) {
sourceFloor = Integer.parseInt(request.replaceAll("[<>]", ""));
if (sourceFloor >= minFloor && sourceFloor <= maxFloor) {
// 检查是否与上一个有效内部请求相同
if (!request.equals(lastValidRequest)) {
elevator.addInternalRequest(sourceFloor);
queue.addInternalRequest(sourceFloor);
lastValidRequest = request;
}
}
}
}
}
System.out.print("Current Floor: 1 Direction: UP");
controller.processRequests();
input.close();
}
}

设计

1.设计思路

RequestQueue:负责管理电梯的请求队列,包括内部请求队列internalRequests和外部请求队列externalRequests。需要改变外请求,由原来的,楼层+方向 转为 楼层+目标楼层
getTargetFloorAndDirection:同时也是需要大量改动,需要程序自动去判断外请求的方向,并且多出来非常多种难以考虑的情况,例外外请求只剩一个时,或者当前楼层和外请求一致时。这些情况都需要去考虑,并且要不断的改进代码,使代码拥有正确处理这些情况的能力。

2.类图

3.代码规模

391 行代码,含 261 条语句

4.复杂度分析


分支语句占比(Percent Branch Statements ):31.0% ,表明代码中条件判断逻辑较多。
最大块深度(Maximum Block Depth )与平均块深度(Average Block Depth ):最大块深度为 7 ,平均块深度 3.69 。意味着代码中控制结构很复杂。
最复杂方法(Name of Most Complex Method ):Elevator.getTargetFloorAndDirection() 方法最为复杂,行数 85 行,复杂度达 75 。该方法集中大量复杂逻辑,可读性与可维护性差,修改时易引入新问题。
其他指标
方法调用语句数(Method Call Statements ):80 条,说明代码通过较多方法调用来组织功能。
注释比例(Percent Lines with Comments ):仅 1.3% ,注释严重不足,不利于他人。
平均复杂度(Average Complexity ):8.92 ,表明代码整体复杂度非常高。

三.踩坑心得

由于程序结构没设计好,每一次迭代的工作量都巨大。我这三次迭代走的最大的弯路,就是使用穷举法时考虑不全面。
譬如第一次迭代作业,忽略内请求等于外请求的情况,导致每当内请求外请求相等时,程序不会执行任何语句,目标楼层不会改变,最后直接把targetfloor的初始值-1作为目标楼层。

因为代码太过于复杂,我一直认为是代码的其他地方出了问题,并没有往这方面考虑,甚至怀疑队列类出了问题,可是做了大量的修改后问题并没有解决。外加调试时不会设置断点调试,我的查错过程变得无比的艰难。这使得我无法第一时间判断出代码到底哪里有问题,做了很多无用功。
最后经过不断的思考,硬是想出来了代码的逻辑漏洞,并且成功修改,在最开始就考虑内请求和外请求一致的情况。

第三次迭代作业又是同样的问题困扰了我,因为程序的算法改变,一种新的特殊情况出现了,那就是当前楼层和内请求一致。当这种情况出现时,程序又会发生和上次一样的情况,电梯直接回到-1楼。

原因是因为moveToFloor类中,当内请求和外请求一致时,会同时删除两个请求。而我一直以为是getTargetFloorAndDirection类出了问题。最后被逼无奈,学会了设置断点,成功找到错误。
可以说设断点这个技能,我交了十几个小时的学费。因为之前学c语言甚至是做课程设计我都没有使用断点调试,所以一直没有这个习惯,可悲的是直到现在我才学会这样好用且重要的方法。
除此之外,写代码时的功利心太强也是一大错误。写代码时由于迫切想写出题目,完全没有去考虑类的复用性和封装性,导致之后的迭代付出了更大的代价。作为一名未来的程序员,重视代码的规范性是必要的职业操守。
最后,现在重新去看最复杂的getTargetFloorAndDirection类,其实有许多可以改进的地方,什么时候判断代码为空,什么时候判断特殊情况,这些都是可以值得去思考的,而我总是图方面,把代码改的非常不科学。还有判断下一个请求的逻辑,其实主要分为:判断方向是否一致,判断哪个请求更近。如果可以设置为额外的方法的话可以减少不少代码行数。

四.改进建议

经过三次作业,在不断的修改中,我也明白了我代码存在的一些问题。
1.代码结构问题
代码的的结构太乱,且一开始就考虑的不全面,使得代码的复杂度高居不下。导致要修改算法的时候非常麻烦。
2.复用性问题
java语言一个非常大的优势就是复用性,而我也是在第三次迭代才意思到自己代码的复用性太差了。
3.注释
注释非常重要,注释可以帮助自己和别人理解代码,而我这次代码没有过多考虑注释问题。
4.命名
正确规范地给类命名也很重要
5.单一职责
如果再有几次迭代的话,我想我会增加几个类,尽可能实现单一职责原则。

五.总结

经过这三次作业的磨练,我的收获还是很大的。以后再次面对大量的if-else语句时,我对于如何设计类便会胸有成竹。同时,我思考情况是也会更加严谨,要在一开始是就考虑所有的特殊情况,判断完所有特殊情况之后,在去考虑其他情况。
熟练设置断点是我最大的收获,这是我以后面对复杂代码的制胜法宝。同时我也发现,Idea中其实有大量的工具等着我去使用。
大型程序的设计和小型程序有很多不同,要遵守更多原则,要在更多的地方更加规范,而这种能力是初学者欠缺且非常需要学习的。

posted on 2025-04-20 16:27  24201632-徐健  阅读(9)  评论(0)    收藏  举报