哈工大软件构造Lab3
2020年春季学期计算机学院《软件构造》课程Lab 3实验报告
1实验目标概述
本次实验覆盖课程第3、4、5章的内容,目标是编写具有可复用性和可维护性的软件,主要使用以下软件构造技术:
- 子类型、泛型、多态、重写、重载、继承、代理、组合
- 常见的OO设计模式
- 语法驱动的编程、正则表达式
- 基于状态的编程
- API设计、API复用
本次实验针对三个具体应用(高铁车次管理、航班管理、大学课表管理),通过ADT和泛型等抽象技术,开发一套可复用的ADT及其实现,充分考虑这些应用之间的相似性和差异性,使ADT有更大程度的复用(可复用性)和更容易面向各种变化(可维护性)。
2实验环境配置
3实验过程
3.1 待开发的三个应用场景
本次开发的三个应用场景:
- 航班管理
- 高铁车次管理
- 大学课表管理
共性:
应用启动,取消,完成,分配资源,时间均在创建时设定,setter和getter
个性:
- 位置的数量分别为2个,多个,1个
- 大学课表位置可改
- 资源数量分别为1个,多个,一个
- 高铁车次可挂起
3.2 面向可复用性和可维护性的设计:PlanningEntry。
3.2.1 PlanningEntry的共性操作
PlanningEntry设计为一个接口,用五个方法来实现状态的转换,
getter获取location、timeslot等一些信息。
setter设定状态转变时需要用到
进而,设计一个类CommonPlanningEntry来实现PlanningEntry,并实现PlanningEntry中的所有方法。
3.2.2 局部共性特征的设计方案
在任何一个维度上分别定义自己的接口,针对每个维度的不同特征取值,分别实现对该维度的接口的不同实现类,实现其逻辑操作。以资源为例:
3.2.3 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)
通过接口组合,将各种局部共性行为复合在一起,形成满足每个应用要求的特殊接口,从而该应用可直接实现该组合接口。在应用子类中,通过delegation到外部每个维度上的各具体实现类的相应特殊逻辑操作。以飞机航班为例:
Junit测试:
3.3 面向复用的设计:R
Resource被设计为一个接口,有3个实现类:AircraftResource、CarriagResourcee和TeacherResource。Resource接口中有3种子类的静态工厂方法。
Junit测试:
3.4 面向复用的设计:Location
仅代表一个位置
复用设计每个维度分别定义其接口和实现类
Junit测试:
3.5 面向复用的设计:Timeslot
用两个List存储出发时间和到达时间,若只用一个地点,两个list的第一个元素分贝存储各自信息,若有多个地点,最后一个地点的出发时间为null,第一个地点的到达时间为null,两个list的长度相等且等于地点的个数。
Junit测试:
3.6 面向复用的设计:EntryState及State设计模式
定义一个EntryState接口并给出所有状态改变的对应方法,然后实现每个状态的具体类。
以RUNNINGState为例,能到达的状态return true,并设置为新状态,不能到达的状态return false。
3.7 面向应用的设计:Board
三个Board均为各个应用的具体实现类,以FlightBoard为例,每个机场有1小时内到达航班和起飞航班的显示,以FlightEntryCollection为成员变量方便遍历所有计划项。还有一个现在时间的Calendar变量。
3.8 Board的可视化:外部API的复用
首先对PlanningEntry进行遍历,获得时间该航班的(到达/起飞)时间,与当前时间进行比对,若差距在预设的范围内(HOURS_RANGE=1)便将该PlanningEntry的信息记录到Vector上,再将该Vector加入二维Vector上,该二维Vector用于生成JTable。在各Board类中实现方法:public void visualize()用于实现Board的可视化。
可视化效果:
3.9 可复用API设计及Façade设计模式
首先实现一个PlanningEntryCollection的ADT,该ADT是PlanningEntry的集合类,存储所有计划项、位置和资源以及管理他们。主要有有以下功能:新建一个计划项,分配资源,board可视化,查询状态,操作某个计划项。
对于APIs定义三个集合类成员变量以便后续操作直接delegation出去。
3.9.1 检测一组计划项之间是否存在位置独占冲突
只有学习课程存在位置冲突,遍历所有计划项,如果两个计划项的位置相同,检查他们的时间是否冲突。
3.9.2 检测一组计划项之间是否存在资源独占冲突
操作与上一方法类似,代码级别复用。
3.9.3 提取面向特定资源的前序计划项
首先初始化一个最晚时间,遍历所有计划项,选出使用相同资源的计划项如果比原最晚时间还晚,则更新最晚时间,同时更新前序计划项。
3.10 设计模式应用
3.10.1 Factory Method
在PlanningEntry接口中设置3个静态工厂方法分别创建各自应用的具体类。以FlightEntry为例:
3.10.2 Iterator
新建comparator对象,重写compare方法。
3.10.3 Strategy
在抽象类Strategy中设置抽象方法:使用StrategyA和StrategyB两个具体类来实现这个方法。
3.11 应用设计与开发
3.11.1 航班应用
(1)初始界面采用网格布局管理器
(二)可视化窗口
添加动作ActionListener按下按钮,启动该功能的专属的可视化窗口。
(三)新建计划项
采用网格组布局管理器,后续窗口的布局都采用这种模式。按下Enter键后,获取5个文本框中的字符串,delegation调用添加计划项的方法。
(四)分配资源
与上述方法一致,获取文本框中的信息,通过按钮按键实现其功能
(五)询问状态
与上述方法一致
(六)操作计划项
与上述方法一致,使用下拉列表框来表示状态的可选项
(七)APIs:检查冲突,寻找前置计划项
与上述方法一致
(八)同一资源的计划项
与上述方法一致
(九)管理位置
与上述方法一致
(十)管理资源
与上述方法一致
3.11.2 高铁应用
与上述类似,差别在于新建计划项
采用形如TrainStation:”Nanchang jinan beijing”, Times:”2020-02-02 12:00 2020-02-02 13:00 2020-02-02 14:00 2020-02-02 15:00”的方式输入
3.11.3 进程应用
3.11.4 课表应用
与上述方式一致,区别在于新增改变地点的功能按键
3.11.5 学习活动应用
3.12 基于语法的数据读入
根据数据的格式,设计正则表达式,并对读入的数据进行匹配,然后提取信息,新建计划项。
3.13 应对面临的新变化
3.13.1 变化1
航班管理从两个站变成三个站,把它继承的TwoLocationEntry替换成MultipleLocationEntry,delegation重写新方法,火车应用的代码复用。
3.13.2 变化2
高铁管理若分配资源则不能被取消,通过重写cancel方法,增加判断语句限制即可。
3.13.3 变化3
课程管理可以挂起,重写block即可。