南昌航空大学-软件学院-面向对象程序设计-JAVA-Blog(一)
一、前言
目前学习《面向对象程序设计》这门课程已经快八周了。对于Java和C语言之间的区别,最直观的就是java相比于C语言有较多的库方法,但在设计方面需要多花心思。关于Java这门语言的学习,也在第五周迎来了首次大作业,于第八周迭代完成。本次大作业经历了三次迭代,三次迭代的难度是循序渐进的,对结构的设计要求也是精益求精。除大作业以外,还有三次题目集,主要围绕Java的结构,类的使用,还有一些函数的知识。本篇Blog主要是对迭代作业以及三次题目集的概要分析。
二、设计与分析
java题目集(五):
于第五周发布,在该次作业中共有5道习题,进一步要求学生使用定义类以及类方法,第一次迭代作业《单部电梯调度程序》首次亮相,同时要求学生能够使用正则表达式解决题目。其中我将主要分析 5-3:验证码校验 和 5-5:单部电梯调度程序。
————————————————————————————————————————————————————————————————
5-3 NCHU_正则表达式训练-验证码校验
接受给定的字符串,判断该字符串是否属于验证码。验证码是由四位数字或者字母(包含大小写)组成的字符串。
输入格式:
在一行内输入一个字符串。
输出格式:
判断该字符串是否符合验证码规则,若是验证码,输出字符串是验证码,否则输出字符串不是验证码。
输入样例1:
在这里给出一组输入。例如:
123A
输出样例1:
在这里给出相应的输出。例如:
123A属于验证码
输入样例2:
在这里给出一组输入。例如:
12?AD
输出样例2:
在这里给出相应的输出。例如:
12?AD不属于验证码
我的代码:
点击查看代码
import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Main{
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
String s=sc.next();
String regex="^[a-zA-Z0-9]{4}$";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(s);
if(matcher.matches()){
System.out.println(s+"属于验证码");
}
else{
System.out.println(s+"不属于验证码");
}
}
}
正则表达式的用途
正则表达式可用于多种文本处理场景,如:
验证输入:检验用户输入是否符合特定格式,像邮箱地址、手机号码、身份证号码等。
搜索文本:在大段文本中查找符合特定模式的内容。**
替换文本:将文本里符合某种模式的部分替换成其他内容。
分割文本:按照特定模式把文本分割成多个部分。
正则表达式在 Java 里是处理文本的有力工具,学习正则表达式可以在特定场景发挥用途,方便快捷。
————————————————————————————————————————————————————————————————
5-5 NCHU_单部电梯调度程序
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为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
题目分析
5-5 NCHU_单部电梯调度程序这道题目对于当时的我们说是降维打击也不为过,复杂的算法应该是学习编程以来第一次遇到。但是好在老师给出提示以及对输入样例作出解释后,加上9天的努力,许多同学还是完成了这道题。
我的代码:
点击查看代码
import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.ArrayList;
// 电梯运行方向枚举
enum Direction {
UP, DOWN, IDLE
}
// 电梯运行状态枚举
enum Status {
STOPPED, MOVING, OPENING, CLOSING
}
class Elevator {
private int min = 1;
private int max = 1;
private int cur = 1;
private Direction direction = Direction.IDLE; //UP, DOWN, IDLE
private Status status = Status.STOPPED; //STOPPED, MOVING, OPENING, CLOSING
private ArrayList<Integer> internalRequests = new ArrayList<>();
private ArrayList<String> externalRequests = new ArrayList<>();
public Elevator() {
}
public Elevator(int min, int max) {
this.min = min;
this.max = max;
this.cur = min;
}
public int getMin() {
return min;
}
public void setMin(int min) {
this.min = min;
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getCur() {
return cur;
}
public void setCur(int cur) {
this.cur = cur;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public ArrayList<Integer> getInternalRequests() {
return internalRequests;
}
public void setInternalRequests(ArrayList<Integer> internalRequests) {
this.internalRequests = internalRequests;
}
public ArrayList<String> getExternalRequests() {
return externalRequests;
}
public void setExternalRequests(ArrayList<String> externalRequests) {
this.externalRequests = externalRequests;
}
//增加内部请求
public void addInternalRequest(int floor) {
internalRequests.add(floor);
}
//增加外部请求(UP/DOWN)
public void addExternalRequest(int floor, Direction dir) {
String str = String.valueOf(floor);
externalRequests.add(str);
if (dir == Direction.UP) {
externalRequests.add("UP");
}
else if (dir == Direction.DOWN) {
externalRequests.add("DOWN");
}
}
//开关门操作(只在电梯类内使用)
private void openDoor() {
System.out.println("Open Door # Floor " + cur);
status = Status.OPENING;
}
private void closeDoor() {
System.out.println("Close Door");
status = Status.CLOSING;
status = Status.MOVING;
}
public void move() {
if(Direction.UP.equals(direction)) {
cur++;
System.out.println("Current Floor: "+cur+" Direction: "+direction);
}
else{
cur--;
System.out.println("Current Floor: "+cur+" Direction: "+direction);
}
}
public int calculateFloor() {
String s = externalRequests.get(0);
char c = s.charAt(0);
int floor = c-'0';
return floor;
}
public void processRequests(){
while(true){
if (internalRequests.isEmpty() && externalRequests.isEmpty()) { //完成所有请求后退出
direction = Direction.IDLE;
status = Status.STOPPED;
return;
}
else if(internalRequests.isEmpty()){
int exFloor = calculateFloor();
int flag=0;
while(exFloor!=cur){
if(exFloor>cur){
direction = Direction.UP;
move();
}
else{
direction = Direction.DOWN;
move();
}
}
openDoor();
closeDoor();
externalRequests.remove(0);
externalRequests.remove(0);
}
else if(externalRequests.isEmpty()){
int inFloor = internalRequests.get(0);
while(inFloor!=cur){
if(inFloor>cur){
direction = Direction.UP;
move();
}
else{
direction = Direction.DOWN;
move();
}
}
openDoor();
closeDoor();
internalRequests.remove(0);
}
else{
int inFloor =internalRequests.get(0);
int exFloor = calculateFloor();
int in=Math.abs(inFloor-cur);
int ex=Math.abs(exFloor-cur);
if(in<ex){
while(cur!=inFloor){
if(inFloor>cur){
direction=Direction.UP;
move();
}
else{
direction = Direction.DOWN;
move();
}
}
openDoor();
closeDoor();
internalRequests.remove(0);
}
else if(in>ex){
while(cur!=exFloor){
if(exFloor>cur){
direction = Direction.UP;
move();
}
else{
direction = Direction.DOWN;
move();
}
}
openDoor();
closeDoor();
externalRequests.remove(0);
externalRequests.remove(0);
}
else{
while(cur!=inFloor){
if(inFloor>cur){
direction = Direction.UP;
move();
}
else{
direction = Direction.DOWN;
move();
}
}
openDoor();
closeDoor();
internalRequests.remove(0);
externalRequests.remove(0);
externalRequests.remove(0);
}
}
}
}
}
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<String> list = new ArrayList<>(); //用于接收用户输入的数组
data = input.next();
while(!data.equalsIgnoreCase("END")){ //输入以“end”结束
list.add(data);
data = input.next();
}
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.println("Current Floor: 1 Direction: UP");
elevator.processRequests(); //一次性处理所有的内、外部乘客请求
input.close();
}
}
代码分析
下面是对以上代码的大致解释
由于是首次的迭代,只是粗糙的分为了Elevator类和Main类。其中Main类使用了正则表达式对输入样例进行数据提取,而Elevator类则十分复杂。
从SourceMonitor对我的代码的分析就可以看的出来我第一次的代码非常垃圾,只是达到了能过测试点的程度。
自我反省:
1.注释占比过低,后期理解和维护代码难度大,尤其对新接手代码人员不友好。
2.主方法复杂度高,违反高内聚低耦合原则,一旦出错排查困难,也不利于代码复用。
我也问了AI,豆包给出的建议是补充注释提升可读性,对复杂主方法拆分优化,进一步均衡各指标以提高代码质量 。
心路历程
第一次写这种题目在刚开始我是根本没在怕的,所谓初生牛犊不怕虎嘛。但是发现分析题目真正意思就花了一整天时间后,心气就没有那么高了。从代码大体完成到编译错误再到一次次的答案错误,导致那几天的心情也不是很晴。但在程序课上经过老师讲解后,也是终于发现了自己的错误所在,于是又花了两天去修改算法逻辑问题。这九天的Java学习相比与之前的C语言学习对我来说是差异巨大的,上学期的C语言的平时作业可以不费吹灰之力完成,平时考试的题目也谈不上多难,但这次的Java大作业却不一样,面临复杂的算法有时真是无从下手。但好在都过去了,车到山前必有路,柳暗花明又一村。我相信这九天的学习、处处碰壁并非白白浪费,对于解决实质性编程问题肯定是有帮助的。
————————————————————————————————————————————————————————————————
java题目集(六):
于第六周发布,在该次作业中共有3道习题,均为类设计题目,第三题对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题。其中我将主要分析 6-3 NCHU_单部电梯调度程序(类设计) 。
6-3 NCHU_单部电梯调度程序(类设计)
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,具体设计可参考如下类图。
电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
注意:本次作业类设计必须符合如上要求(包含但不限于乘客请求类、电梯类、请求队列类及控制类,其中控制类专门负责电梯调度过程),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次电梯程序提交到本次题目中测试)。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
输入样例1:
在这里给出一组输入。例如:
1
20
< 3,UP>
<5>
<6,DOWN>
<7>
<3>
end
输出样例1:
在这里给出相应的输出。例如:
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
输入样例2:
在这里给出一组输入。例如:
1
20
< 3,UP>
< 3,UP>
<5>
<5>
<5>
<6,DOWN>
<7>
<7>
<3>
<22,DOWN>
<5,DOWN>
<30>
END
输出样例2:
在这里给出相应的输出。例如:
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
Open Door # Floor 5
Close Door
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door
题目分析
第二次迭代要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,并给出了参考类图,同时加入了特殊情况及边界性测试,使题目更加严谨,贴合实际情况。
我的代码
点击查看代码
import java.util.Scanner;
import java.util.ArrayList;
// 电梯运行方向枚举
enum Direction {
UP, DOWN, IDLE
}
// 电梯运行状态枚举
enum Status {
STOPPED, MOVING
}
class RequestList{//队列请求函数
private ArrayList<Integer> internalRequests = new ArrayList<>();//内部请求
private ArrayList<String> externalRequests =new ArrayList<>();//外部请求
public RequestList(){
}
public RequestList(ArrayList<Integer> internalRequests, ArrayList<String> externalRequests){
this.internalRequests = internalRequests;
this.externalRequests = externalRequests;
}
public ArrayList<Integer> getInternalRequests(){
return internalRequests;
}
public void setInternalRequests(ArrayList<Integer> internalRequests){
this.internalRequests = internalRequests;
}
public ArrayList<String> getExternalRequests(){
return externalRequests;
}
public void setExternalRequests(ArrayList<String> externalRequests){
this.externalRequests = externalRequests;
}
//增加内部请求
public void addInternalRequest(int floor) {
internalRequests.add(floor);
}
//增加外部请求(UP/DOWN)
public void addExternalRequest(int floor, Direction dir) {
String str = String.valueOf(floor);
externalRequests.add(str);
if (dir == Direction.UP) {
externalRequests.add("UP");
}
else if (dir == Direction.DOWN) {
externalRequests.add("DOWN");
}
}
//移除内部请求
public void removeInternalRequest(){
internalRequests.remove(0);
}
//移除外部请求
public void removeExternalRequest(){
externalRequests.remove(0);
externalRequests.remove(0);
}
}
class Elevator{//电梯类
private int curFloor=1;
private int minFloor=1;
private int maxFloor=1;
private Status status=Status.STOPPED;
private Direction direction=Direction.IDLE;
public Elevator(){
}
public Elevator(int minFloor, int maxFloor){
this.minFloor=minFloor;
this.maxFloor=maxFloor;
this.curFloor=minFloor;
}
public int getCurFloor(){
return curFloor;
}
public void setCurFloor(int curFloor){
this.curFloor = curFloor;
}
public int getMinFloor(){
return minFloor;
}
public int getMaxFloor(){
return maxFloor;
}
public Status getStatus(){
return status;
}
public Direction getDirection(){
return direction;
}
public void setDirection(Direction direction){
this.direction = direction;
}
}
class Controller{//控制类(主要)
private Elevator elevator=new Elevator();
private RequestList requestList=new RequestList();
public Controller(){
}
public Controller(Elevator elevator, RequestList requestList){
this.elevator=elevator;
this.requestList=requestList;
}
public Elevator getElevator(){
return elevator;
}
public void setElevator(Elevator elevator){
this.elevator=elevator;
}
public RequestList getRequestList(){
return requestList;
}
public void setRequestList(RequestList requestList){
this.requestList=requestList;
}
//开关门操作
private void openDoor() {
System.out.println("Open Door # Floor " + elevator.getCurFloor());
}
private void closeDoor() {
System.out.println("Close Door");
}
//计算外部请求楼层
public int calculateFloor() {
String s = requestList.getExternalRequests().get(0);
char c = s.charAt(0);
return c-'0';
}
public void move(){
if(Direction.UP.equals(elevator.getDirection())) {
elevator.setCurFloor(elevator.getCurFloor()+1);
System.out.println("Current Floor: "+elevator.getCurFloor()+" Direction: "+elevator.getDirection());
}
else{
elevator.setCurFloor(elevator.getCurFloor()-1);
System.out.println("Current Floor: "+elevator.getCurFloor()+" Direction: "+elevator.getDirection());
}
}
public void processRequest(){
while(true){
if (requestList.getInternalRequests().isEmpty() && requestList.getExternalRequests().isEmpty()) { //完成所有请求后退出
elevator.setDirection(Direction.IDLE);
return;
}
else if(requestList.getInternalRequests().isEmpty()){
int exFloor = calculateFloor();
while(exFloor!=elevator.getCurFloor()){
if(exFloor>elevator.getCurFloor()){
elevator.setDirection(Direction.UP);
move();
}
else{
elevator.setDirection(Direction.DOWN);
move();
}
}
openDoor();
closeDoor();
requestList.removeExternalRequest();
}
else if(requestList.getExternalRequests().isEmpty()){
int inFloor = requestList.getInternalRequests().get(0);
while(inFloor!=elevator.getCurFloor()){
if(inFloor>elevator.getCurFloor()){
elevator.setDirection(Direction.UP);
move();
}
else{
elevator.setDirection(Direction.DOWN);
move();
}
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
else{
int exFloor = calculateFloor();
int inFloor = requestList.getInternalRequests().get(0);
if (inFloor >= elevator.getCurFloor() && exFloor >= elevator.getCurFloor()) {
elevator.setDirection(Direction.UP);
String dir = requestList.getExternalRequests().get(1);
if (dir.equals("UP")) {
if (inFloor > exFloor) {
while (exFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeExternalRequest();
}
else if(inFloor<exFloor){
while(inFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
else{
while(inFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
requestList.removeExternalRequest();
}
}
else if (dir.equals("DOWN")) {
while (inFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
}
else if(inFloor<elevator.getCurFloor()&&exFloor<elevator.getCurFloor()){
elevator.setDirection(Direction.DOWN);
String dir = requestList.getExternalRequests().get(1);
if(dir.equals("DOWN")){
if(inFloor>exFloor){
while(inFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
else if(inFloor<exFloor){
while(exFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeExternalRequest();
}
else{
while(inFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
requestList.removeExternalRequest();
}
}
else if (dir.equals("UP")){
while (inFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
}
else{
if(exFloor>inFloor){
if(elevator.getDirection().equals(Direction.UP)){
while(exFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
String dir = requestList.getExternalRequests().get(1);
if(dir.equals(Direction.DOWN)){
elevator.setDirection(Direction.DOWN);
}
requestList.removeExternalRequest();
}
else if(elevator.getDirection().equals(Direction.DOWN)){
while(inFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
}
else{
if(elevator.getDirection().equals(Direction.UP)){
while(inFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
else if(elevator.getDirection().equals(Direction.DOWN)){
while(exFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
String dir = requestList.getExternalRequests().get(1);
if(dir.equals(Direction.UP)){
elevator.setDirection(Direction.UP);
}
requestList.removeExternalRequest();
}
}
}
}
}
}
}
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 = ""; //提取出的乘客请求字符串
String lastRequest = null;//用于判断是否输入连续请求
ArrayList<String> list = new ArrayList<>(); //用于接收用户输入的数组
data = input.next();
while(!data.equalsIgnoreCase("END")){ //输入以“end”结束
list.add(data);
data = input.next();
}
minFloor = Integer.parseInt(list.get(0));//第一行,电梯最低楼层
maxFloor = Integer.parseInt(list.get(1));//第二行,电梯最高楼层
RequestList requestList = new RequestList();//创建请求队列对象
for(int i = 2; i < list.size(); i++){//从第三行开始为乘客请求
request = list.get(i);
if (request.equals(lastRequest)) {
continue; // 如果当前请求和上一个请求相同,忽略该请求
}
lastRequest = request;
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());
if(floor>=minFloor&&floor<=maxFloor){
requestList.addExternalRequest(floor, direction);//外部请求入队,格式为<楼层数,方向>
}
}else{
if (!request.matches("<\\d+>")) {//内部请求
System.out.println("Wrong Format");
}
floor = Integer.parseInt(request.replaceAll("[<>]", ""));
if(floor>=minFloor&&floor<=maxFloor){
requestList.addInternalRequest(floor);//内部请求入队,格式为<楼层数>
}
}
}
System.out.println("Current Floor: 1 Direction: UP");
Elevator elevator=new Elevator(minFloor,maxFloor);//创建电梯请求对象
Controller controller = new Controller(elevator, requestList);
controller.processRequest();//一次性完成所有请求
input.close();
}
}
代码分析
有了上一次的基础,少了复杂的算法,这次迭代就相对简单了许多。代码除了将原有的Elevaotr类保留,还按要求增添了RequestList队列请求类和Controller控制类以实现职责单一原则。
函数复杂度相关
从上图分析可知,最复杂的方法是 Controller.processRequest(),行号为 154 。较高的行数意味着方法做了过多的事情,违背了单一职责原则,这是从第一次迭代遗留的历史难题,可我到了第三次迭代也未能将其解决。
函数深度相关
从 Block Histogram(语句数与深度的柱状图)来看,深度为 7 时语句数较多。意味着方法中可能存在多层嵌套,如多层 if - else、循环嵌套等,这会使代码的可读性和可维护性大大降低。没错,Controller.processRequest()为处理电梯运行逻辑运用了大量的if - else,悲。
心路历程
大楼不可能平地而起,代码也是如此。这次迭代作业之所以没像上次那样花费大量精力,就是因为只增加了两个类,修改不到两小时,提交就有了满分。
————————————————————————————————————————————————————————————————
java题目集(七):
于第七周发布,在该次作业中共有3道习题,均为类设计题目,第三题对之前电梯调度程序进行迭代性设计,在上一次的基础上,加入乘客类(Passenger),取消乘客请求类(RequestLsit)。其中我将主要分析 7-3 NCHU_单部电梯调度程序(类设计) 。
7-3 NCHU_单部电梯调度程序(类设计-迭代)
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考如下类图。
电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
注意:本次作业类设计必须符合如上要求(包含但不限于设计电梯类、乘客类、队列类以及控制类),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次及第二次电梯程序提交到本次题目中测试)。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
输入样例1:
在这里给出一组输入。例如:
1
20
<5,4>
<5>
<7>
end
输出样例1:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
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
Current Floor: 5 Direction: DOWN
Open Door # Floor 5
Close Door
Current Floor: 4 Direction: DOWN
Open Door # Floor 4
Close Door
输入样例2:
在这里给出一组输入。例如:
1
20
<5,9>
<8>
<9,3>
<4>
<2>
end
输出样例2:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
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
Current Floor: 8 Direction: UP
Open Door # Floor 8
Close Door
Current Floor: 9 Direction: UP
Open Door # Floor 9
Close Door
Current Floor: 8 Direction: DOWN
Current Floor: 7 Direction: DOWN
Current Floor: 6 Direction: DOWN
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Open Door # Floor 4
Close Door
Current Floor: 3 Direction: DOWN
Current Floor: 2 Direction: DOWN
Open Door # Floor 2
Close Door
Current Floor: 3 Direction: UP
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Current Floor: 8 Direction: UP
Current Floor: 9 Direction: UP
Open Door # Floor 9
Close Door
Current Floor: 8 Direction: DOWN
Current Floor: 7 Direction: DOWN
Current Floor: 6 Direction: DOWN
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door
我的代码
点击查看代码
import java.util.Scanner;
import java.util.ArrayList;
// 电梯运行方向枚举
enum Direction {
UP, DOWN, IDLE
}
// 电梯运行状态枚举
enum Status {
STOPPED, MOVING
}
class RequestList{
private ArrayList<Passenger> internalRequests = new ArrayList<>();
private ArrayList<Passenger> externalRequests = new ArrayList<>();
public RequestList(){
}
public RequestList(ArrayList<Passenger> internalRequests, ArrayList<Passenger> externalRequests){
this.internalRequests = internalRequests;
this.externalRequests = externalRequests;
}
public ArrayList<Passenger> getInternalRequests(){
return internalRequests;
}
public void setInternalRequests(ArrayList<Passenger> internalRequests){
this.internalRequests = internalRequests;
}
public ArrayList<Passenger> getExternalRequests(){
return externalRequests;
}
public void setExternalRequests(ArrayList<Passenger> externalRequests){
this.externalRequests = externalRequests;
}
//增加内部请求
public void addInternalRequest(Passenger p) {
internalRequests.add(p);
}
//增加外部请求(UP/DOWN)
public void addExternalRequest(Passenger p) {
externalRequests.add(p);
}
//移除内部请求
public void removeInternalRequest(){
internalRequests.remove(0);
}
//移除外部请求
public void removeExternalRequest(){
//将<请求源楼层,请求目的楼层>中的请求目的楼层加入到内部队列(加到队尾)
int floor=externalRequests.get(0).getDestFloor();
addInternalRequest(new Passenger(floor));
externalRequests.remove(0);
}
}
class Elevator{
private int curFloor=1;
private int minFloor=1;
private int maxFloor=1;
private Status status=Status.STOPPED;
private Direction direction=Direction.IDLE;
public Elevator(){
}
public Elevator(int minFloor, int maxFloor){
this.minFloor=minFloor;
this.maxFloor=maxFloor;
this.curFloor=minFloor;
}
public int getCurFloor(){
return curFloor;
}
public void setCurFloor(int curFloor){
this.curFloor = curFloor;
}
public int getMinFloor(){
return minFloor;
}
public int getMaxFloor(){
return maxFloor;
}
public Status getStatus(){
return status;
}
public Direction getDirection(){
return direction;
}
public void setDirection(Direction direction){
this.direction = direction;
}
}
class Passenger{
private int floor=1;
private int destFloor=1;
public Passenger(){
}
public Passenger(int floor){
this.floor=floor;
}
public Passenger(int floor, int destFloor){
this.floor=floor;
this.destFloor=destFloor;
}
public int getFloor(){
return floor;
}
public void setFloor(int floor){
this.floor = floor;
}
public int getDestFloor(){
return destFloor;
}
public void setDestFloor(int destFloor){
this.destFloor = destFloor;
}
}
class Controller{
private Elevator elevator=new Elevator();
private RequestList requestList=new RequestList();
public Controller(){
}
public Controller(Elevator elevator, RequestList requestList){
this.elevator=elevator;
this.requestList=requestList;
}
public Elevator getElevator(){
return elevator;
}
public void setElevator(Elevator elevator){
this.elevator=elevator;
}
public RequestList getRequestList(){
return requestList;
}
public void setRequestList(RequestList requestList){
this.requestList=requestList;
}
//开关门操作
private void openDoor() {
System.out.println("Open Door # Floor " + elevator.getCurFloor());
}
private void closeDoor() {
System.out.println("Close Door");
}
public void move(){
if(Direction.UP.equals(elevator.getDirection())) {
elevator.setCurFloor(elevator.getCurFloor()+1);
System.out.println("Current Floor: "+elevator.getCurFloor()+" Direction: "+elevator.getDirection());
}
else{
elevator.setCurFloor(elevator.getCurFloor()-1);
System.out.println("Current Floor: "+elevator.getCurFloor()+" Direction: "+elevator.getDirection());
}
}
public void processRequest(){
while(true){
if (requestList.getInternalRequests().isEmpty() && requestList.getExternalRequests().isEmpty()) { //完成所有请求后退出
elevator.setDirection(Direction.IDLE);
return;
}
else if(requestList.getInternalRequests().isEmpty()){
int exFloor = requestList.getExternalRequests().get(0).getFloor();
while(exFloor!=elevator.getCurFloor()){
if(exFloor>elevator.getCurFloor()){
elevator.setDirection(Direction.UP);
move();
}
else{
elevator.setDirection(Direction.DOWN);
move();
}
}
openDoor();
closeDoor();
requestList.removeExternalRequest();
}
else if(requestList.getExternalRequests().isEmpty()){
int inFloor = requestList.getInternalRequests().get(0).getFloor();
while(inFloor!=elevator.getCurFloor()){
if(inFloor>elevator.getCurFloor()){
elevator.setDirection(Direction.UP);
move();
}
else{
elevator.setDirection(Direction.DOWN);
move();
}
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
else{
int exFloor = requestList.getExternalRequests().get(0).getFloor();
int inFloor = requestList.getInternalRequests().get(0).getFloor();
int exFloor1= requestList.getExternalRequests().get(1).getFloor();
if (inFloor >= elevator.getCurFloor() && exFloor >= elevator.getCurFloor()) {
elevator.setDirection(Direction.UP);
if (inFloor > exFloor && exFloor<exFloor1) {
while (exFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeExternalRequest();
} else if (inFloor < exFloor) {
while (inFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
} else {
if(exFloor<exFloor1){
while (inFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
requestList.removeExternalRequest();
}
}
}
else if(inFloor<elevator.getCurFloor()&&exFloor<elevator.getCurFloor()){
elevator.setDirection(Direction.DOWN);
if (inFloor > exFloor) {
while (inFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
} else if (inFloor < exFloor) {
while (exFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeExternalRequest();
} else {
while (inFloor != elevator.getCurFloor()) {
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
requestList.removeExternalRequest();
}
}
else{
if(exFloor>inFloor){
if(elevator.getDirection().equals(Direction.UP)){
while(exFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeExternalRequest();
}
else if(elevator.getDirection().equals(Direction.DOWN)){
while(inFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
}
else{
if(elevator.getDirection().equals(Direction.UP)){
while(inFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeInternalRequest();
}
else if(elevator.getDirection().equals(Direction.DOWN)){
while(exFloor!=elevator.getCurFloor()){
move();
}
openDoor();
closeDoor();
requestList.removeExternalRequest();
}
}
}
}
}
}
}
public class Main{
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String data; //输入数据:字符串
int floor = 0;
int destFloor=0;
//Direction direction = null;
int minFloor,maxFloor; //电梯最低楼层、最高楼层
String request = ""; //提取出的乘客请求字符串
String lastRequest = null;//用于判断是否输入连续请求
ArrayList<String> list = new ArrayList<>(); //用于接收用户输入的数组
data = input.next();
while(!data.equalsIgnoreCase("END")){ //输入以“end”结束
list.add(data);
data = input.next();
}
minFloor = Integer.parseInt(list.get(0));//第一行,电梯最低楼层
maxFloor = Integer.parseInt(list.get(1));//第二行,电梯最高楼层
RequestList requestList = new RequestList();//创建请求队列对象
for(int i = 2; i < list.size(); i++){//从第三行开始为乘客请求
request = list.get(i);
if (request.equals(lastRequest)) {
continue; // 如果当前请求和上一个请求相同,忽略该请求
}
lastRequest = request;
if(request.contains(",")){//外部请求
if (!request.matches("<\\d+,\\d+>")) {
System.out.println("Wrong Format");
}
String[] parts = request.replaceAll("[<>]", "").split(",");
floor = Integer.parseInt(parts[0].trim());
destFloor = Integer.parseInt(parts[1].trim());
if(floor>=minFloor&&floor<=maxFloor){
requestList.addExternalRequest(new Passenger(floor,destFloor));//外部请求入队,格式为<楼层数,方向>
}
}else{
if (!request.matches("<\\d+>")) {//内部请求
System.out.println("Wrong Format");
}
floor = Integer.parseInt(request.replaceAll("[<>]", ""));
if(floor>=minFloor&&floor<=maxFloor){
requestList.addInternalRequest(new Passenger(floor));//内部请求入队,格式为<楼层数>
}
}
}
System.out.println("Current Floor: 1 Direction: UP");
Elevator elevator=new Elevator(minFloor,maxFloor);//创建电梯请求对象
Controller controller = new Controller(elevator, requestList);
controller.processRequest();//一次性完成所有请求
input.close();
}
}
代码分析
心路历程
到了第三次,加入乘客类(Passenger),取消乘客请求类,并在输入格式上做了些许变化,但对电梯运行逻辑并未产生过多影响。加入乘客类(Passenger)对于RequestList来说相当于把整形数组改为了对象数组,也未产生过多影响,总而言之,我还是觉得第一次的电梯题目难。
————————————————————————————————————————————————————————————————
三、踩坑心得
回顾不到一年的编程之旅,没有哪次踩得坑有这一个月踩得多,何尝不是一种幸福。
以下是我记住的一些雷点:
1. 审题不清
审题可以说是贯穿学生生涯的一个能力,关键信息理解错误将会酿成大错。在第一次阅读电梯题目时,没有审清题干就动手导致白白浪费了一天。要想培养审题能力也很简单如逐字阅读:在看题时,不要着急动手写代码,要逐字逐句地去读题目内容,防止遗漏重要信息。比如,题目要求计算某个范围内的质数个数,“某个范围” 就是关键信息,你要准确把握这个范围的边界。或多问自己问题:读完题目后,多问自己一些问题,比如 “题目要求实现什么功能?”“有哪些输入和输出?” 以一个简单的题目为例,若题目是 “编写一个 Java 程序,计算两个整数的和并输出结果”,你可以问自己 “输入的两个整数有没有范围限制?”“输出结果的格式有要求吗?”以避免二次修改代码。
2. 先搞懂再下手
第一次看到电梯的输入样例时,脑子里只有对于ArrayList很模糊的概念,只是知道可能要用这个知识点,但具体怎么写却不清楚。但我却直接动手写代码了,这是非常错误的抉择,以至于后面走了弯路。对于尚未搞懂的知识点,理应先学懂,这样运用起来也不会磕磕绊绊。
3. 柳暗花明又一村
想必每个人都遇到过改代码改的死去活来的时候,本人不喜熬夜,于是晚上代码写不出来的时候我会选择早睡。以此为例,我认为在面对一时半会无法理清的题,不如放下,出去散散心,正所谓山重水复疑无路,柳暗花明又一村嘛。
————————————————————————————————————————————————————————————————
四、改进建议
给自己
希望在下一次的迭代作业,自己能够尽量做到以下两点。
代码注释:在代码中添加适当的注释,解释代码的功能和实现思路,也方便自己和他人理解代码。
代码复用:避免重复编写功能相同的代码,将常用的功能封装成函数或类,提高代码的复用性。
给辛勤的课题组
首先感谢面向对象程序设计课题组对于教学的辛勤付出,以及在学习Java过程中对同学的保驾护航,无论遇到什么问题都会及时给出答复,非常神通广大。
在第一次大作业中,为避免学生利用ai编写代码,将常规电梯逻辑改为了非一般的电梯逻辑,在前一周属实是让大多数同学摸不着头脑,给出的运行样例也不够具有代表性,个人认为这样不利于进行初次的代码编写。
————————————————————————————————————————————————————————————————
五、总结
关于这次大作业的心路历程已经在每次的代码后总结了,这里便不做过多阐述。谈及收获的话我想每个人都是满满当当的,对我来说,一次次的提交显示绿油油的非零返回或答案错误就是一次次砥砺心境,现在的我明显强于一个月以前的我。希望下一个月能够继续保持斗志吧,结束。