设计一个电梯模拟器
2个要点: 1. 这个不只是一个解决方案,2.过程比结论重要。
如何分析USE CASE?做一些必要的假设。
主要功能,
a. 按按钮请求一个电梯
b. 等电梯来
c. 乘坐电梯
不同组件之间应该如何交互?
a. 输入输出是什么?
Request -> schedule evlevator -> load onto elevator -> schedule elevator -> unload
b. 提供弹性针对未来不同的实现。
what do we need to model?
- something visible
elevators, users, floors;
要记住不要过度设计。
过度设计的坏处:理解代码 很难理解。运行效率低。
过度设计的判断依据?
依靠设计好的USE CASE,当前的设计是简单还是复杂。
- something invisible
scheduling 算法, requests , instruction sent by scheduler to the elevator
一个电梯有什么?
状态: 移动方向,容量,门的状态,当前位置,按钮的状态
行为: 移动,开门,关门, get/set 方向。
public interface Scheduler {
// given the state of the system, update elevator states
void schedule(List<Queue<Integer>> requests, List<Elevator> elevators, int floor);
}
package Elevator;
import java.util.Queue;
public class Elevator {
private static final int DEFAULT_MAX_CAPACITY = 14;
private static final int DEFAULT_MAX_FLOOR = 10;
private static final int DEFAULT_INITIAL_LOCATION = 1;
private final int maxCapacity;
private final int maxFloor;
private int load;
private int location;
private boolean isGoingUp;
private int[] requests;
public Elevator(int maxCapacity, int maxFloor) {
this.maxCapacity = maxCapacity;
this.maxFloor = maxFloor;
load = 0;
location = DEFAULT_INITIAL_LOCATION;
isGoingUp = true;
requests = new int[maxFloor];
}
public Elevator() {
this(DEFAULT_MAX_CAPACITY, DEFAULT_MAX_FLOOR);
}
public boolean isEmpty() {
return load == 0;
}
public boolean isFull() {
return load >= maxCapacity;
}
public int getLocation() {
return location;
}
public int move() {
if (isGoingUp) {
return (location + 1 <= maxFloor) ? ++location : location;
} else {
return location - 1 >= 1 ? --location : location;
}
}
public boolean changeMovingDirection() {
isGoingUp = !isGoingUp;
return isGoingUp;
}
public int load(Queue<Integer> curQueue) {
int numNewLoad = curQueue.size();
if (load + numNewLoad > maxCapacity) {
return 0;
}
for (int requestedFloor : curQueue) {
requests[requestedFloor - 1] += 1;
}
load += numNewLoad;
System.out.println("elevator load " + numNewLoad+" people on "+location+" floor");
System.out.println("elevator have " + load +" people");
curQueue.clear();
return numNewLoad;
}
public int unload() {
int numReq = requests[location - 1];
if (numReq > 0) {
load -= numReq;
requests[location - 1] = 0;
System.out.println("elevator unload " + numReq+" people on "+location+" floor");
System.out.println("elevator have " + load +" people");
return numReq;
}
return 0;
}
}
package Elevator;
import java.util.*;
public class Simulator {
//how many floors
private final int floors;
//all user requests
private List<Queue<Integer>> requests;
// all elevators in system
private List<Elevator> elevators;
//current elevator scheduler we use
private Scheduler scheduler;
public Simulator(int floors, int numElevators, List<Queue<Integer>> initialRequests,
Scheduler scheduler, int elevatorCapacity) {
this.floors = floors;
this.requests = initialRequests;
this.elevators = new ArrayList<Elevator>();
for (int i = 0; i < numElevators; i++) {
Elevator ele = new Elevator(elevatorCapacity, floors);
elevators.add(ele);
}
this.scheduler = scheduler;
}
private void generateRequest() {
}
private void schedule() {
scheduler.schedule(requests, elevators, floors);
}
private void elevatorOp() {
for (Elevator e : elevators) {
if (!e.isEmpty()) {
e.unload();
}
if (!e.isFull()) {
int location = e.getLocation();
e.load(requests.get(location - 1));
}
e.move();
}
}
//handle to start the simulation
public void simulate(int steps) throws InterruptedException {
for (int i = 0; i < steps; i++) {
generateRequest();
schedule();
elevatorOp();
Thread.sleep(10);
}
}
// entry point of the simulation program
public static void main(String[] args) throws InterruptedException {
SimpleScheduler simpleScheduler = new SimpleScheduler();
int floors = 10;
int numElevators = 1;
List<Queue<Integer>> initialRequests = new ArrayList<>();
for (int i = 0; i < floors; i++) {
Queue<Integer> currQueue = new LinkedList<>();
Random r = new Random();
int req = r.nextInt(10);
currQueue.offer(req + 1);
initialRequests.add(currQueue);
}
Simulator simulator = new Simulator(floors, numElevators, initialRequests, simpleScheduler, 14);
simulator.simulate(20);
}
private static class SimpleScheduler implements Scheduler {
@Override
public void schedule(List<Queue<Integer>> requests, List<Elevator> elevators, int floor) {
for (Elevator e : elevators) {
if (e.getLocation() == 1 || e.getLocation() == floor) {
e.changeMovingDirection();
}
}
}
}
}