3.1 待开发的三个应用场景
1、 航班管理
2、 高铁车次管理
3、 学习日程管理
异同点:位置数量分别为1,2,多个
仅有学习日程位置可更改
分别为单个、有序多个、无序多个
仅有高铁车次可阻塞
3.2 面向可复用性和可维护性的设计:PlanningEntry
该节是本实验的核心部分。
3.2.1 PlanningEntry的共性操作
3个工厂方法分别能够返回指定类型的PlanningEntry实现类,以Flight Schedule为例
public static FlightSchedule newPlanningEntryOfFlightSchedule(Location location, TimeSlot timeSlot,
String planningEntryNumber) {
return new FlightSchedule(location, timeSlot, planningEntryNumber);
}
状态的转换,以目标状态进行分类,能够将状态转换为RUNNING、BLOCKED、CANCELLED、ENDED四种之一(其中转换为ALLOCATED是个性化设计),分别用4个方法来实现。
3.2.2 局部共性特征的设计方案
CommonPlanningEntry类实现了PlanningEntry接口中共性方法,包括了状态转换和Getter方法。
状态转换,以Start()为例:将状态转换委派给state对象的Setter操作,通过常量来进行目标状态的区分。在state对象中,首先判断该转换是否合法(访问EntryStateEnum静态常量进行判断),然后在进行状态覆盖,最后返回操作成功与否的标识。
3.2.3面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)
3个子类型的不同主要在于两方面:Location、TimeSlot、Resource等信息的存储模式和信息的修改。
存储模式:在我的设计中,信息存储的差异统一合并到“信息对象”的内部中,通过不同子类型的不同Getter来得到相应的信息细节。信息对象具体设计在3.3-3.6说明。
以Flight Schedule为例,getLocationOrigin()、getLocationTerminal()方法获得了起飞、降落机场;而在Activity Calendar中则用getStrLocation()获得活动地点。
3.3 面向复用的设计:R
资源有多种,因为Resource被设计为一个接口,有3个实现类:Plane、Train和Document。Resource接口中有3种子类的工厂方法。
其中publishDate在构造时用String输入,降低前置条件,并在构造方法中转换。
3.4 面向复用的设计:Location
由于我选择的3种计划项位置数量各不相同,因此我采用一个List来存储若干的位置,通过PlanningEntry的不同Getter来获取。
而location 本身是一个存储多个字符串的组合
3.5 面向复用的设计:Timeslot
Time Slot和Location是共同设计的,存储有两个List,分别代表对应的位置的到达和离开时间。由此设计,可以精确到每个地点的到达和离开时间,若为第一个地点,则到达和离开时间相同;若为最后一个地点也如此;若只有一个地点,则也如此。
由此,3种不同的计划项,通过不同的Getter实现不同的特征。
3.6 面向复用的设计:EntryState及State设计模式
EntryState是一个可变对象,成员变量有类型为enum的state
private EntryStateEnum state;
在构造方法中,通过字符串参数toUpperCase,再对应到EntryStateEnum中的某一个枚举,进行初始化。
判断合法性的工作交给另一个范围值为Boolean的方法setAvailability(),而该方法又将这项工作委派给EntryStateEnum中的静态Map变量。该Map分为两种,一种是可能被Block的,一种则不行。判断是否可以Block的工作在EntryStateEnum中进行,用一个List来保存可以Block的类型的关键字(增强鲁棒性)。
3.7 面向应用的设计:Board
Board是每个地方的信息板,以机场为例,每个机场有1小时内到达航班和起飞航班的显示。Board是一个抽象类,有3个不同的实现类,分别完成3个应用场景的Board。在初始化时,保存PlanningEntryCollection作为成员变量,以便遍历PlanningEntry。
3.8 Board的可视化:外部API的复用
首先获得PlanningEntryCollection的PlanningEntry进行遍历,获得时间该航班的(到达/起飞)时间,与当前时间进行比对,若差距在预设的范围内(HOURS_RANGE=1)便将该PlanningEntry的信息记录到Vector上,再将该Vector加入二维Vector上,该二维Vector用于生成JTable。
Board.makeTable()中新建JTable,将信息输入表格,再将表格加入JFrame,委派JFrame进行可视化。
3.9 可复该ADT是PlanningEntry的集合类。
3.9.1 检测一组计划项之间是否存在位置独占冲突
考察List是否有冲突,要遍历任意两个计划项,是否存在这时间重叠。对于任意两个不同计划项c1、c2,分别获取它们的起始时间和结束时间,进行比较:若一方的起始时间早于另一方的结束时间且结束时间晚于起始时间,则认为冲突。
3.9.2 检测·一组计划项之间是否存在资源独占冲突
考察List是否有冲突,要遍历任意两个计划项,是否存在这时间重叠。对于任意两个不同计划项p1、p2,分别获取它们的起始时间和结束时间,进行比较:若一方的起始时间早于另一方的结束时间且结束时间晚于起始时间,则认为冲突。
返回true表示冲突,返回false表示无冲突。
3.9.3 提取面向特定资源的前序计划项
首先初始最晚时间和前序计划项
遍历所有计划项选出相同的计划项
迭代比较,符合条件则更新