首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >电梯设计

电梯设计
EN

Code Review用户
提问于 2019-12-31 21:26:00
回答 1查看 1.2K关注 0票数 4

我想设计一个电梯系统,它具有从电梯外部按下按钮的功能(而不是选择一个方向,只打电话给乘客现有的楼层)。还可以选择为目标选择地板所需的地板功能。

内部控件比外部控件具有优先级。

在旅行的时候,电梯只有在途中才能停站(通过外部控制)。我尝试过实现状态模式,但它并没有像我预期的那样起作用。

请您评论一下我如何改进以下解决方案。

谢谢。

Elevator.java

代码语言:javascript
复制
package OOPDesign.elevatorStates;

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

public class Elevator {

    public static Elevator instance;

    static Queue requestQueue;
    static ElevatorStateContext elevatorStateContext;
    static int currentFloor;

    private Elevator(){
        requestQueue = new LinkedList<>();
        elevatorStateContext = new ElevatorStateContext();
        currentFloor = 0;
    }

    public static Elevator getInstance(){
        if(instance == null){
            instance = new Elevator();
        }
        return instance;
    }

    static void receiveRequest(int passengersFloor){
        requestQueue.add(passengersFloor);

        processQueue(requestQueue);
    }

    static void processQueue(Queue requestQueue) {

        int passengersFloor = requestQueue.peek();
        System.out.println("Currently going "+ passengersFloor);
        if(passengersFloor>currentFloor)
            elevatorStateContext.setState(State.UP);
        else
            elevatorStateContext.setState(State.DOWN);
        System.out.println("Direction "+ elevatorStateContext.getDirection());
        requestQueue.remove();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Arrived "+ passengersFloor);
        if(requestQueue.isEmpty()){
            elevatorStateContext.setState(State.IDLE);
            System.out.println("Direction "+ elevatorStateContext.getDirection());
        }
    }


}

ElevatorControlSystem.java

代码语言:javascript
复制
package OOPDesign.elevatorStates;

public class ElevatorControlSystem {

    Elevator elevator;

    public ElevatorControlSystem(){
        elevator = Elevator.getInstance();
    }

    void pressButton(int passengersFloor){
        dispatchRequest("OUTSIDE",passengersFloor);
    }


    void selectFloor(int targetFloor){
        dispatchRequest("INSIDE",targetFloor);
    }

    private void dispatchRequest(String priority, int passengersFloor) {

        int elevatorFloor = Elevator.currentFloor;
        // If elevator is idle it can serve to any request
        if(Elevator.elevatorStateContext.getDirection() == State.IDLE){
            Elevator.receiveRequest(passengersFloor);
        }else {

            if (priority == "INSIDE") {
                Elevator.receiveRequest(passengersFloor);
            } else { // Outside calls
                if (Elevator.elevatorStateContext.getDirection() == State.UP && passengersFloor > elevatorFloor) {
                    Elevator.receiveRequest(passengersFloor);
                } else if (Elevator.elevatorStateContext.getDirection() == State.DOWN && passengersFloor < elevatorFloor) {
                    Elevator.receiveRequest(passengersFloor);
                } else {
                    System.out.println("Can not give service");
                }
            }
        }

    }
}

ElevatorState.java

代码语言:javascript
复制
package OOPDesign.elevatorStates;

interface ElevatorState {

    public State status(ElevatorStateContext ctx);
}

ElevatorStateContext.java

代码语言:javascript
复制
package OOPDesign.elevatorStates;

public class ElevatorStateContext {

    private State elevatorState;

    public ElevatorStateContext(){
        elevatorState = State.IDLE;
    }

    public void setState(State state){
        elevatorState = state;
    }

    public State getDirection(){
        return elevatorState;
    }

}

Enum

代码语言:javascript
复制
package OOPDesign.elevatorStates;

public enum State {
    IDLE,
    UP,
    DOWN;
}

测试类

代码语言:javascript
复制
package OOPDesign.elevatorStates;

public class ElevatorTest {

    public static void main(String[] args) {

        ElevatorControlSystem ecs = new ElevatorControlSystem();

        ecs.pressButton(5);

        ecs.selectFloor(3);

        ecs.pressButton(6);
        ecs.selectFloor(1);
        ecs.pressButton(9);
        ecs.pressButton(10);
        ecs.pressButton(11);

    }
}
EN

回答 1

Code Review用户

发布于 2020-01-01 22:04:19

如果这个设计是为了一个学校的项目,而你已经提交了它,我担心你已经失败了。这个设计很糟糕。

静态

作为指导原则,Java程序应该准确地使用标识符static一次,特别是在声明public static void main(String args[])中。static的任何其他用法都应该发出警告;您可能做错了什么。

考虑一家酒店。它通常有多个电梯。有了static int currentFloor,每部电梯都必须在同一层!有了static ElevatorStateContext elevatorStateContext,所有的电梯都朝同一个方向移动!这是一个糟糕的设计选择。即使只有一个电梯,电梯也应该拥有自己的数据,而不是将其存储为全局类变量。

通常,酒店有多个电梯系统。可能有一个主要的电梯银行,为客人,以及服务电梯为酒店工作人员。酒店的多个塔楼里可能有电梯,还有停车场的电梯。简而言之,可能有多个ElevatorControlSystem,每个人都拥有自己的一套电梯。每次构造ElevatorControlSystem时,它都执行elevator = Elevator.getInstance(); .这意味着每个控制系统都试图操作同一个电梯?

身份-vs-平等

测试if (priority == "INSIDE")正在测试对象标识。只有当存储在String中的priority与嵌入在此编译单元中的String具有相同的标识时,测试才能通过。这是脆弱的,一旦尝试传入在其他地方创建的字符串"INSIDE",就会中断。您应该检查是否相等:if (priority.equals("INSIDE"))

或者,为INSIDE -vs- OUTSIDE使用一个D19-vs- D20,就像您已经用于电梯状态一样。

无用项目

无用封装

ElevatorStateContext包含State elevatorState、setter和getter,它们不添加额外的行为、检查或功能。

这门课的目的是什么?您可以直接在State中存储和获取Elevator,并消除该类。或者应该包括在ElevatorStateContext中的其他东西,比如门是开/开/关/关,还是要求在哪一层?

无用队列

您有一个队列,它最多只能容纳一个项目。这些行添加项,然后立即取出项进行处理:

代码语言:javascript
复制
    requestQueue.add(passengersFloor);
    processQueue(requestQueue);

processQueue()中,您可以从队列中分离出peek()remove()项:

代码语言:javascript
复制
    int passengersFloor = requestQueue.peek();
    ...
    requestQueue.remove();
    ...

但是没有必要窥探;您总是删除该项,因此下面的简单代码将起作用:

代码语言:javascript
复制
    int passengersFloor = requestQueue.remove();
    ...

未使用项目

未使用的单例

您执行elevator = Elevator.getInstance();,但实际上在任何地方都没有使用elevator成员变量。

未使用接口

您可以声明interface ElevatorState,但是从来没有实现过该接口。

顺序测试/

操作

由于dispatchRequest()processQueue()一次只处理一个请求,所以当另一个请求出现时,测试代码完全无法测试运行中的电梯。如果5个人要求电梯在一楼,并进入,并按楼层按钮5,2,6,3,4.

代码语言:javascript
复制
    ecs.pressButton(1);
    ecs.selectFloor(5);
    ecs.selectFloor(2);
    ecs.selectFloor(6);
    ecs.selectFloor(3);
    ecs.selectFloor(4);

电梯会移动到5楼,绕过2,3和4。然后它会移动到2楼,绕过4和3。然后它会移动到6楼,绕过3和4。然后它会移动到3楼,绕过4。最后它会移动到4楼。效率太低了。

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/234884

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档