1 实验目标概述
本次实验覆盖课程第 3、4、5 章的内容,目标是编写具有可复用性和可维护性的软件,主要使用以下软件构造技术:
子类型、泛型、多态、重写、重载
继承、代理、组合
常见的 OO 设计模式
语法驱动的编程、正则表达式
基于状态的编程
API 设计、API 复用
本次实验给定了五个具体应用(高铁车次管理、航班管理、操作系统进程管理、大学课表管理、学习活动日程管理),学生不是直接针对五个应用分别编程实现,而是通过 ADT 和泛型等抽象技术,开发一套可复用的 ADT 及其实现,充分考虑这些应用之间的相似性和差异性,使 ADT 有更大程度的复用(可复用性)和更容易面向各种变化(可维护性)。
2 实验环境配置
实验环境设置请参见 Lab-0 实验指南。
除此之外,本次实验需要你在 Eclipse IDE 中安装配置 EclEmma(一个用于
统计 JUnit 测试用例的代码覆盖度的 plugin)。请访问 http://www.eclemma.org,了解 EclEmma 并学习其安装、配置和使用。
本次实验在 GitHub Classroom 中的 URL 地址为:
https://classroom.github.com/a/z9utaaos
3 实验过程
3.1 待开发的三个应用场景
列出你所选定的三个应用:
1、航班管理
2、高铁车次管理
3、学习日程管理
分析三个应用场景的异同,理解需求:
共同点:
三个应用场景的地点与时间都需要提前确定;
三个应用场景在未开始前均可以取消;
三个应用场景在进行中均不可取消;
不同点:
高铁在中间站停车的时候可以取消;
航班与高铁一旦确定就无法更改起始地与目的地,并且确定后高铁还无法更改中间站,但是学习日程确定之后还能够更改地址;
三个应用场景需要不同类型的资源;
3.2 面向可复用性和可维护性的设计:PlanningEntry
3.2.1 PlanningEntry的共性操作
由下图表得:
public boolean planningRunning();启动计划项
public boolean planningCancelled();取消计划项
public boolean planningEnded();完成计划项
public String getPlanningName();得到计划项的“名字”
public String getState();得到计划项当前的状态
3.2.2 局部共性特征的设计方案
两个变量:
plannningName用于存储计划项的“名字”
state是用于保存计划项当前状态的对象引用
方法:
1.public boolean planningRunning():只有在ALLOCATED和BLOCKED状态下,计划项才能启动计划项,并且将计划项的状态state指向Running这个对象;
2. public boolean planningCancelled():只有在WAITING、ALLOCATED和BLOCKED状态下才能取消计划项,并且将计划项的状态state指向Cancelled这个对象;
3. public boolean planningEnded():只有在RUNNING状态下才能取消计划项,并且将计划项的状态state指向Cancelled这个对象;
4. 两个getter:
3.2.3 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)
1.飞机航班:
构造函数:为航班设定计划项名字,时间以及地点,并且将state指向Waiting这个对象;
public boolean planningAllocated(Aircraft ac):只有在WAITING状态下,才能为航班分配飞机,并且将state指向Allocated这个对象;
FlightEntry类中的内部方法,用于设定飞机航班的地点、时间和资源信息;
3个getter:使用String的形式,得到航班的名字、地点、时间和飞机资源的信息;
public String toString():以String的形式,输出航班的所有信息;
航班特定方法的接口:
2.高铁车次:
构造函数:为高铁设定计划项名字,时间以及地点,并且将state指向Waiting这个对象;
public boolean planningAllocated(Trains trains):只有在WAITING状态下,才能为高铁分配列车资源,并且将state指向Allocated这个对象;
public boolean planningBlocked():只有在WAITING状态下,才能阻塞高铁,并且将state指向Blocked这个对象;
TrainEntry类中的内部方法,用于设定高铁的地点、时间和资源信息;
3个getter:使用String的形式,得到高铁的名字、地点、时间和资源的信息;
public String toString():以String的形式,输出高铁的所有信息;
高铁特定方法的接口:
3.学习活动:
构造函数:为学习活动设定计划项名字,时间以及地点,并且将state指向Waiting这个对象;
public boolean planningAllocated(LearningMaterials l):只有在WAITING状态下,才能为学习活动分配学习资料资源,并且将state指向Allocated这个对象;
public boolean changeLocation(Location loc):只有在WAITING和ALLOCATED状态下,才能为学习活动更换活动地点;
ActivityEntry类中的内部方法,用于设定高铁的地点、时间和资源信息;
3个getter:使用String的形式,得到学习活动的名字、地点、时间和资源的信息;
public String toString():以String的形式,输出学习活动的所有信息;
学习活动特定方法的接口:
3.3 面向复用的设计:R
1.飞机Aircraft:
变量:用于存储变量的信息;
构造函数:设定飞机的信息;
4个getter和toString方法:用于得到飞机的信息;
2.列车Trains和车厢Train:
车厢Train:
构造函数:用于设定车厢的信息;
4个getter和toString方法:用于得到车厢的信息;
列车Trains:由一组车厢组成;
public void addATrain(int number, int type, int seating, int yearOfManufacture):往列车中添加一个车厢;
2个不同的构造函数:用于不同情况下生成一个列车实例;
方法一:生成一个仅有列车编号trainsNumber的列车实例,然后通过addATrain方法一节一节添加车厢组成列车;
方法二:直接复制另外一辆已经生成的列车;
3个getter和toSting方法:用于得到列车的信息;
3.学习资料LearingMaterials:
构造函数:
4个getter和toSting方法:用于得到学习资料的信息;
3.4 面向复用的设计:Location
1.Location:用于表示一个具体地点;
两个构造函数:
4个setter:
4个getter:
toString方法:
2. MutipleLoaction:有多个地点的计划项使用该类存储地点;
public void setLocs(LinkedList locs):用于设定一组地址;
addLocs方法:用于添加一个地址;
2个getter:以String得到地址的信息;
toString:用于得到所有地址的信息;
3. SingleLocation:只有一个地点的计划项使用该类存储地点;
两个setter:用于设定地址;
4个getter和toString方法:用于得到地址的信息;
3.5 面向复用的设计:Timeslot
1.Time:用于存储一个具体的时间点;
2.TimeSlot:由两个Time实例组成,构成一个时间段;
2个Setter:用于设定起始和终止的时间;
public String getBetweenTime():用于计算并得到,活动时长;
2个getter:以String的形式得到起始和终止时间的信息;
3.SingleTime:用于只有一个时间段的计划项的时间存储;
4.MutipleTime:用于有多个时间段的计划项的时间存储,由一组<TimeSlot,String>组成,String用于存储计划项在该时间段的状态;
3.6 面向复用的设计:EntryState及State设计模式
1.StateEntry:作为所有状态的父类;
通过5个boolean变量来表示不同的状态,isBlocked只有在BLOCKED下才为true,其他状态均为false,可以视为isBlocked仅用于BLOCKED状态中,在其他状态中忽略isBlocked;
当前状态的getter,以String形式输出状态,分别有:
“WAITING”、“ALLOCATED”、“RUNNING”、“ENDED”、“CANCELLED”、“BLOCKED”,
分别在具体之类中实现;
5个getter:分别得到当前状态下的五个boolean变量;
2.Waiting:
isRunning = false;
isAllocated = false;
isEnded = false;
isCancelled = false;
3.Allocated:
isRunning = false;
isAllocated = true;
isEnded = false;
isCancelled = false;
4.Running:
isRunning = true;
isAllocated = true;
isEnded = false;
isCancelled = false;
5.Ended:
isRunning = true;
isAllocated = true;
isEnded = false;
isCancelled = false;
6.Cancelled:
isCancelled = true;
7.Blocked:
isBlocked = true;
isRunning = false;
isAllocated = true;
isEnded = false;
isCancelled = false;
3.7 面向应用的设计:Board
1.ActivityBoard:
Activities用于存储一系列的活动计划项;
Time用于存储当前的时间;
Location用于存储Board所展示的活动所处于的地点;
3个setter和一个add方法用于设置Board的当前状况;
从所有的计划项中得到活动地点位于Location的计划项;
使计划项按照计划开始时间的先后进行排列,是Board更加美观;
public void visualize() {
JFrame frame = new JFrame("活动计划");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel1 = new JPanel();
panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS));
String s = time.getTime() + ", " + location.getName();
JLabel label = new JLabel(s, JLabel.CENTER);
panel1.add(label);
String[] columnName = new String[] { "时间", "活动名", "状态" };
ArrayList<String[]> as = new ArrayList<String[]>();
activitiesSortInTime();
LinkedList<ActivityEntry> als = searchActivityEntryByLocation();
for (ActivityEntry al : als) {
SingleTime st = al.getSt();
TimeSlot ts = st.getTime();
if (time.inADay(ts.getBegin()) || time.inADay(ts.getEnd())) {
String[] s1 = new String[] { ts.getBegin().getHourAndMinute() + "-" + ts.getEnd().getHourAndMinute(),
al.getPlanningName(), al.getState() };
as.add(s1);
}
}
String[][] columnDate = (String[][]) as.toArray(new String[0][0]);
JTable table = new JTable(columnDate, columnName);
JScrollPane JSP = new JScrollPane(table);
panel1.add(JSP);
Container p = frame.getContentPane();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
frame.add(panel1);
frame.setSize(800, 400);
frame.setVisible(true);
}
2. FlightBoard:
将一组航班计划项分别按照出发地和目的地使Location筛选出来;
得到以Location为目的地的航班的当前状态;
得到以Location为出发地的航班的当前状态;
public void visualize() {
JFrame frame = new JFrame("飞机航班");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel1 = new JPanel();
panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS));
String s = time.getTime() + ", " + location.getName();
JLabel label = new JLabel(s, JLabel.CENTER);
panel1.add(label);
JLabel label1 = new JLabel("抵达航班", JLabel.CENTER);
panel1.add(label1);
String[] columnName1 = new String[] { "预计抵达时间", "航班号", "出发地-目的地", "状态" };
ArrayList<String[]> fs1 = new ArrayList<String[]>();
LinkedList<FlightEntry> fdds = searchFlightEntryByDestination();
for (FlightEntry fdd : fdds) {
Time end = fdd.getSingleTime().getTime().getEnd();
long betweenTimeInMillis = end.getTimeInMillis() - time.getTimeInMillis();
if (Math.abs(betweenTimeInMillis) <= 1000 * 60 * 60) {
String state = getddState(fdd, betweenTimeInMillis);
String[] s1 = new String[] { end.getTime(), fdd.getPlanningName(),
fdd.getDeparture() + "-" + fdd.getDestination(), state };
fs1.add(s1);
}
}
String[][] columnDate1 = (String[][]) fs1.toArray(new String[0][0]);
JTable table1 = new JTable(columnDate1, columnName1);
JScrollPane JSP1 = new JScrollPane(table1);
panel1.add(JSP1);
JPanel panel2 = new JPanel();
panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS));
JLabel label2 = new JLabel("起飞航班", JLabel.CENTER);
panel2.add(label2);
String[] columnName2 = new String[] { "预计起飞时间", "航班号", "出发地-目的地", "状态" };
ArrayList<String[]> fs2 = new ArrayList<String[]>();
LinkedList<FlightEntry> fqfs = searchFlightEntryByDeparture();
for (FlightEntry fqf : fqfs) {
Time begin = fqf.getSingleTime().getTime().getBegin();
long betweenTimeInMillis = begin.getTimeInMillis() - time.getTimeInMillis();
if (Math.abs(betweenTimeInMillis) <= 1000 * 60 * 60) {
String state = getqfState(fqf, betweenTimeInMillis);
String[] s2 = new String[] { begin.getTime(), fqf.getPlanningName(),
fqf.getDeparture() + "-" + fqf.getDestination(), state };
fs2.add(s2);
}
}
String[][] columnDate2 = (String[][]) fs2.toArray(new String[0][0]);
JTable table2 = new JTable(columnDate2, columnName2);
JScrollPane JSP2 = new JScrollPane(table2);
panel2.add(JSP2);
Container p = frame.getContentPane();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
frame.add(panel1);
frame.add(panel2);
frame.setSize(800, 400);
frame.setVisible(true);
}
3. TrainBoard:
从一组高铁车次中筛选出经过Location的车次;
public LinkedHashMap<Integer, String[]> boundaryCondition(TrainEntry train, boolean isCancelled) {
LinkedHashMap<Integer, String[]> result = new LinkedHashMap<Integer, String[]>();
MutipleTime mt = train.getMt();
MutipleLoaction ml = train.getMl();
String departure = ml.getDeparture();
String destination = ml.getDestination();
if (location.getName().equals(departure)) {
Map.Entry<TimeSlot, String> entry = mt.getTimes().entrySet().iterator().next();
if ((entry.getKey().getBegin().getTimeInMillis() - time.getTimeInMillis()) <= 1000 * 60 * 60) {
String s = "已取消";
if (!isCancelled)
s = "即将出发";
String[] s1 = new String[] { entry.getKey().getBeginTime(), train.getPlanningName(),
departure + "-" + destination, s };
result.put(1, s1);
}
return result;
}
if (location.getName().equals(destination)) {
Iterator<Entry<TimeSlot, String>> entry = mt.getTimes().entrySet().iterator();
Entry<TimeSlot, String> tail = null;
while (entry.hasNext()) {
tail = entry.next();
}
if ((time.getTimeInMillis() - tail.getKey().getEnd().getTimeInMillis()) <= 1000 * 60 * 60) {
String s = "已取消";
if (!isCancelled)
s = "已到达";
String[] s2 = new String[] { tail.getKey().getEndTime(), train.getPlanningName(),
departure + "-" + destination, s };
result.put(2, s2);
}
return result;
}
return result;
public LinkedHashMap<Integer, String[]> boundaryCondition(TrainEntry train, boolean isCancelled):得到以Location为起点或者终点的车次的当前情况;
public LinkedHashMap<Integer, String[]> getState(TrainEntry train, boolean isCancelled) {
LinkedHashMap<Integer, String[]> result = new LinkedHashMap<Integer, String[]>();
MutipleTime mt = train.getMt();
MutipleLoaction ml = train.getMl();
String departure = ml.getDeparture();
String destination = ml.getDestination();
int index = 1;
for (Map.Entry<TimeSlot, String> entry : mt.getTimes().entrySet()) {
TimeSlot timeslot = entry.getKey();
if (timeslot.isIn(time)) {
if (index % 2 == 0) {
int i = index / 2;
Location jt = ml.getByIndex(i);
if (jt.getName().equals(location.getName())) {
String s = "已取消";
if (!isCancelled)
s = "经停";
String[] s1 = new String[] { timeslot.getBeginTime(), timeslot.getEndTime(),
train.getPlanningName(), departure + "-" + destination, s };
result.put(3, s1);
return result;
}
return result;
} else {
int i1 = (index - 1) / 2;
int i2 = (index + 1) / 2;
Location cf = ml.getByIndex(i1);
Location dd = ml.getByIndex(i2);
if (cf.getName().equals(location.getName())) {
if ((time.getTimeInMillis() - timeslot.getBegin().getTimeInMillis()) <= 1000 * 60 * 60) {
String s = "已取消";
if (!isCancelled)
s = "已出发";
String[] s2 = new String[] { timeslot.getBeginTime(), train.getPlanningName(),
departure + "-" + destination, s };
result.put(2, s2);
}
return result;
}
if (dd.getName().equals(location.getName())) {
if ((timeslot.getEnd().getTimeInMillis() - time.getTimeInMillis()) <= 1000 * 60 * 60) {
String s = "已取消";
if (!isCancelled)
s = "即将到达";
String[] s3 = new String[] { timeslot.getEndTime(), train.getPlanningName(),
departure + "-" + destination, s };
result.put(1, s3);
}
return result;
}
return result;
}
}
index++;
}
return result;
}
public LinkedHashMap<Integer, String[]> getState(TrainEntry train, boolean isCancelled):得到不以Location为起点或终点,但是经过Location的车次的当前情况;
public void visualize() {
JFrame frame = new JFrame("高铁车次");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel1 = new JPanel();
panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS));
String s = time.getTime() + ", " + location.getName();
JLabel label = new JLabel(s, JLabel.CENTER);
panel1.add(label);
JLabel label1 = new JLabel("抵达车次", JLabel.CENTER);
panel1.add(label1);
JPanel panel2 = new JPanel();
panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS));
JLabel label2 = new JLabel("出发车次", JLabel.CENTER);
panel2.add(label2);
JPanel panel3 = new JPanel();
panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS));
JLabel label3 = new JLabel("经停车次", JLabel.CENTER);
panel3.add(label3);
LinkedList<TrainEntry> psts = searchPassByTrains();
String[] columnName1 = new String[] { "抵达时间", "车次", "出发地-目的地", "状态" };
ArrayList<String[]> ts1 = new ArrayList<String[]>();
String[] columnName2 = new String[] { "出发时间", "车次", "出发地-目的地", "状态" };
ArrayList<String[]> ts2 = new ArrayList<String[]>();
String[] columnName3 = new String[] { "到达时间", "出发时间", "车次", "出发地-目的地", "状态" };
ArrayList<String[]> ts3 = new ArrayList<String[]>();
for (TrainEntry pst : psts) {
boolean isCancelled = false;
if (pst.getState().equals("CANCELLED"))
isCancelled = true;
Map<Integer, String[]> result1 = boundaryCondition(pst, isCancelled);
if (result1.isEmpty()) {
Map<Integer, String[]> result2 = getState(pst, isCancelled);
if (result2.isEmpty())
continue;
else {
Map.Entry<Integer, String[]> entry = result2.entrySet().iterator().next();
int state = entry.getKey();
if (state == 1)
ts1.add(entry.getValue());
if (state == 2)
ts2.add(entry.getValue());
if (state == 3)
ts3.add(entry.getValue());
}
} else {
Map.Entry<Integer, String[]> entry = result1.entrySet().iterator().next();
int state = entry.getKey();
if (state == 2)
ts1.add(entry.getValue());
if (state == 1)
ts2.add(entry.getValue());
}
}
String[][] columnDate1 = (String[][]) ts1.toArray(new String[0][0]);
String[][] columnDate2 = (String[][]) ts2.toArray(new String[0][0]);
String[][] columnDate3 = (String[][]) ts3.toArray(new String[0][0]);
JTable table1 = new JTable(columnDate1, columnName1);
JScrollPane JSP1 = new JScrollPane(table1);
panel1.add(JSP1);
JTable table2 = new JTable(columnDate2, columnName2);
JScrollPane JSP2 = new JScrollPane(table2);
panel2.add(JSP2);
JTable table3 = new JTable(columnDate3, columnName3);
JScrollPane JSP3 = new JScrollPane(table3);
panel3.add(JSP3);
Container p = frame.getContentPane();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
frame.add(panel1);
frame.add(panel2);
frame.add(panel3);
frame.setSize(1000, 400);
frame.setVisible(true);
}
3.8 Board的可视化:外部API的复用
已经在3.7中进行描述
3.9 PlanningEntryCollection的设计
3.10 可复用API设计及Façade设计模式
3.10.1 检测一组计划项之间是否存在位置独占冲突
3.10.2 检测一组计划项之间是否存在资源独占冲突
3.10.3 提取面向特定资源的前序计划项
3.11 设计模式应用
3.11.1 Factory Method
3.11.2 Iterator
3.11.3 Strategy
3.12 应用设计与开发
3.12.1 航班应用
Flights用于存储当前的航班计划项;
Locs用于存储当前可用的地址;
Acs用于存储当前可用的飞机资源;
用于得到用户的输入;
用于设定某个计划项中的时间;
用于设定某个计划项中的出发地和目的地;
从谁当某个计划项中的飞机资源;
用于可用飞机资源的增加或删除;
用于可用地址的增加或删除;
用于判断某个计划项是否在当前计划项列表中;
操作:
public void app() {
System.out.println("Operation list:");
System.out.println("1.Add location;");
System.out.println("2.Delete location;");
System.out.println("3.Add aircraft resources;");
System.out.println("4.Delete aircraft resources;");
System.out.println("5.Add flight plan item;");
System.out.println("6.Assign resources to a flight plan item;");
System.out.println("7.Cancel a flight plan item;");
System.out.println("8.Start a flight plan item;");
System.out.println("9.End a flight plan item;");
System.out.println("10.Get the current status of a flight plan item;");
System.out.println("11.Check whether there is position conflict in all current flight plan items;");
System.out.println("12.Check whether there are resource conflicts in all current flight plan items;");
System.out.println("13.Get the first flight of a flight;");
System.out.println("14.Generate flight planning board according to a certain location;");
System.out.println("15.Exit;");
do {
int operation = Integer.parseInt(getInput("Please enter the operation"));
switch (operation) {
case 1:
addLoc();
break;
case 2:
deleteLocs();
break;
case 3:
addAcs();
break;
case 4:
deleteAcs();
break;
case 5:
addFlight();
break;
case 6:
allocatedFlights();
break;
case 7:
deleteFlights();
break;
case 8:
runningFlights();
break;
case 9:
endFlights();
break;
case 10:
System.out.println(getState());
break;
case 11:
if (checkLocationConflict())
System.out.println("Location Conflict!");
else
System.out.println("No Location Conflict!");
break;
case 12:
if (checkResourceExclusiveConflict())
System.out.println("Resource Exclusive Conflict!");
else
System.out.println("No Resource Exclusive Conflict!");
break;
case 13:
System.out.println(findPreEntryPerResource().toString());
break;
case 14:
showBoard();
break;
case 15:
System.exit(0);
default:
System.out.println("Input Wrong!");
break;
}
} while (true);
}
3.12.2 高铁应用
与之前类似的方法就不进行重复描述,只描述该应用中出现的特有方法;
通过用户输入设定一个列车车厢;
通过用户输入设定一列列车;
用于设定某个计划项的时间;
用于设定某个计划项的地址;
增加的特有操作;
public void app() {
System.out.println("Operation list:");
System.out.println("1.Add location;");
System.out.println("2.Delete location;");
System.out.println("3.Add aircraft resources;");
System.out.println("4.Delete aircraft resources;");
System.out.println("5.Add flight plan item;");
System.out.println("6.Assign resources to a flight plan item;");
System.out.println("7.Cancel a flight plan item;");
System.out.println("8.Start a flight plan item;");
System.out.println("9.End a flight plan item;");
System.out.println("10.Get the current status of a flight plan item;");
System.out.println("11.Check whether there is position conflict in all current flight plan items;");
System.out.println("12.Check whether there are resource conflicts in all current flight plan items;");
System.out.println("13.Get the first flight of a flight;");
System.out.println("14.Generate flight planning board according to a certain location;");
System.out.println("15.Block a flight plan item;");
System.out.println("16.Restrat a flight plan item;");
System.out.println("17.Exit;");
do {
int operation = Integer.parseInt(getInput("Please enter the operation"));
switch (operation) {
case 1:
addLoc();
break;
case 2:
deleteLocs();
break;
case 3:
addTs();
break;
case 4:
deleteTs();
break;
case 5:
addTrains();
break;
case 6:
allocatedTrains();
break;
case 7:
cancelledTrains();
break;
case 8:
runningTrains();
break;
case 9:
endTrains();
break;
case 10:
System.out.println(getState());
break;
case 11:
if (checkLocationConflict())
System.out.println("Location Conflict!");
else
System.out.println("No Location Conflict!");
break;
case 12:
if (checkResourceExclusiveConflict())
System.out.println("Resource Exclusive Conflict!");
else
System.out.println("No Resource Exclusive Conflict!");
break;
case 13:
System.out.println(findPreEntryPerResource().toString());
break;
case 14:
showBoard();
break;
case 15:
blockedTrains();
break;
case 16:
runningTrains();
break;
case 17:
System.exit(0);
default:
System.out.println("Input Wrong!");
break;
}
} while (true);
}
3.12.3 进程应用
3.12.4 课表应用
3.12.5 学习活动应用
增加的特有操作;
3.13 基于语法的数据读入
public void readFromFile() {
int i = Integer.parseInt(getInput("Please enter the number of files to read in"));
ArrayList<String> arrayList = new ArrayList<>();
String name = "src/txt/FlightSchedule_" + String.format("%d", i) + ".txt";
File file = new File(name);
try {
FileReader fr = new FileReader(file);
BufferedReader bf = new BufferedReader(fr);
String str;
while ((str = bf.readLine()) != null) {
arrayList.add(str);
}
bf.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
int length = arrayList.size();
for (int x = 0; x < length; x = x + 13) {
int y = 0;
String l1 = arrayList.get(x + y);
String[] l11 = l1.split(",");
String planningName = l11[1];
y++;
y++;
String l3 = arrayList.get(x + y);
String[] l31 = l3.split(":");
String departAirport = l31[1];
Location departure = new Location();
departure.setName(departAirport);
departure.setIsShareAble(true);
y++;
String l4 = arrayList.get(x + y);
String[] l41 = l4.split(":");
String arrivalAirport = l41[1];
Location arrival = new Location();
arrival.setName(arrivalAirport);
arrival.setIsShareAble(true);
y++;
String l5 = arrayList.get(x + y);
String[] l51 = l5.split("\\s+");
String[] l52 = l51[1].split(":");
int hour = Integer.parseInt(l52[0]);
int minute = Integer.parseInt(l52[1]);
String[] l53 = l51[0].split(":");
String[] l54 = l53[1].split("-");
int year = Integer.parseInt(l54[0]);
int month = Integer.parseInt(l54[1]);
int day = Integer.parseInt(l54[2]);
Time begin = new Time(year, month, day, hour, minute);
y++;
String l6 = arrayList.get(x + y);
String[] l61 = l6.split("\\s+");
String[] l62 = l61[1].split(":");
int hour1 = Integer.parseInt(l62[0]);
int minute1 = Integer.parseInt(l62[1]);
String[] l63 = l61[0].split(":");
String[] l64 = l63[1].split("-");
int year1 = Integer.parseInt(l64[0]);
int month1 = Integer.parseInt(l64[1]);
int day1 = Integer.parseInt(l64[2]);
Time end = new Time(year1, month1, day1, hour1, minute1);
TimeSlot st = new TimeSlot(begin, end);
y++;
String l7 = arrayList.get(x + y);
String[] l71 = l7.split(":");
String number = l71[1];
y++;
y++;
String l9 = arrayList.get(x + y);
String[] l91 = l9.split(":");
String type = l91[1];
y++;
String l10 = arrayList.get(x + y);
String[] l101 = l10.split(":");
int seating = Integer.parseInt(l101[1]);
y++;
String s11 = arrayList.get(x + y);
String[] s111 = s11.split(":");
double age = Double.parseDouble(s111[1]);
Aircraft a = new Aircraft(number, type, seating, age);
FlightEntry fe = new FlightEntry(planningName, st, departure, arrival);
fe.planningAllocated(a);
flights.add(fe);
}
}
3.14 应对面临的新变化
3.14.1 变化1
航班支持经停
原来的:
参数中的改变,只需要将存储时间的参数st类变为MutipleTime
改变后:
如何将st的setter和getter进行相应的改变;
原来的Getter:
改变后:只需要改变返回值
原来的Setter:是调用SingleTime类中方法进行赋值
改变后的Setter:调用MutipleTime中类的方法进行赋值,可以直接复制TrainEntry中的方法,因为现在两者存储时间的类型都是MutipleTime,设置时间的操作相同,只是添加多少时间对不一样而已,并且将调用改变后setter的方法相应的接口进行改变即可;
但是由于之前的测试函数是按照无经停情况进行编写的,需要将测试函数重新编写;
还需要再FlightEntry中加入blocked状态对应的方法,变化方法与变化3类似,因此在变化3中在进行仔细讲解,现在就给出个结果。
添加public boolean planningBlocked():
重写其父类CommonPlanningEntry中的方法public boolean planningCancelled():
3.14.2 变化2
高铁车次分配了列车后,无法取消;
原来的:位于CommonPlanningEntry类中;
改变后:在TrainEntry类中重写该方法
3.14.3 变化3
活动执行后可以阻塞
在ActivityEntry类中增加一个方法public boolean planningBlocked():
在ActivityEntry类中重写其父类CommonPlanningEntry中的方法public boolean planningCancelled()
由于TrainEntry现在的状态转移图跟ActivityEntry一致,两个方法均可以从TrainEntry中直接复制。