Reusability and Maintainability Oriented Programming
- 1 实验目标概述
- 2 实验环境配置
- 3 实验过程
- 3.1 待开发的三个应用场景
- 3.2 面向可复用性和可维护性的设计:PlanningEntry
- 3.2.1 PlanningEntry的共性操作
- 3.2.3 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)
- 3.10.1 检测一组计划项之间是否存在位置独占冲突
- 3.10.2 检测一组计划项之间是否存在资源独占冲突
- 3.10.3 提取面向特定资源的前序计划项
- 3.11.1 Factory Method
- 3.11.2 Iterator
- 3.11.3 Strategy
- 3.14.1 变化1
- 3.14.2 变化2
- 3.14.3 变化3
1 实验目标概述
本次实验覆盖课程第 3、4、5 章的内容,目标是编写具有可复用性和可维护性的软件,主要使用以下软件构造技术:
子类型、泛型、多态、重写、重载
继承、代理、组合
常见的 OO 设计模式语法驱动的编程、正则表达式
基于状态的编程
API设计、API复用
本次实验给定了五个具体应用(高铁车次管理、航班管理、操作系统进程管理、大学课表管理、学习活动日程管理),学生不是直接针对五个应用分别编程实现,而是通过 ADT 和泛型等抽象技术,开发一套可复用的 ADT 及其实现,充分考虑这些应用之间的相似性和差异性,使ADT有更大程度的复用(可复用性)和更容易面向各种变化(可维护性)。
2 实验环境配置
●建立本地git仓库
cd D:\\eclipse-workspace\\Lab3_1180300621
d:
dir
git init //生成.git目录
git add * //该目录下所有文件纳入git管理【文件->暂存区】
git status //具体信息
git commit -m “v0.1 All code in main()” //创建待提交的数据结构【暂存区->本地仓库】
git log //查看提交信息
git remote add origin “仓库地址”
git push -u -f origin master【本地仓库->线上仓库】
————————————————————————————————
●在这里给出你的GitHub Lab3仓库的URL地址(Lab3-学号)。
3 实验过程
3.1 待开发的三个应用场景
列出你所选定的三个应用。
●航班管理
●高铁车次管理
●学习日程管理
分析三个应用场景的异同,理解需求:它们在哪些方面有共性、哪些方面有差异。
●时间可在创建时设定;
●只有学习日程的位置可更改;
●只有高铁的状态可阻塞
●航班为单个资源、高铁为多个有序资源、学习日程为多个无序资源
————————————————————————————————
3.2 面向可复用性和可维护性的设计:PlanningEntry
航班·计划项 | 资源 | 单个可区分,单架飞机 | |
---|---|---|---|
飞机·类 | 编号 | string | |
机型 | string | ||
座位数 | int | ||
机龄 | double | ||
地点·类(可设定、不可更改) | 起点 | ||
经停站 | |||
终点 | |||
时间·类(可设定) | 一个起止时间对 | ||
状态(不可阻塞) | waiting:航班信息确定、未分配飞机;allocated:已分配飞机、未起飞;running:航班已起飞;ended:航班已抵达;cancelled:航班未起飞前被取消,不再执飞 | ||
高铁·计划项 | 资源 | 多个带次序可区分资源,车厢的集合(动车组) | |
车厢·类 | 唯一编号 | string | |
类型 | string | ||
定员数 | int | ||
使用时长 | double | ||
地点·类(可设定、不可更改) | 起点 | ||
一组中间位置 | |||
终点 | |||
时间·类(可设定) | 一组起止时间对 | ||
状态(可阻塞) | waiting:航班信息确定、未分配车厢;allocated:已分配一组车厢、未发车;running:已从起始站发车;blocked:抵达某个中间站,停ended:高铁已抵达;cancelled:高铁未发车前被取消/或在某个中间站被取消 | ||
活动·计划项 | 资源 | 多个不带次序、不需区分ID的资源(如100份学习资料) | |
学习材料·类 | 材料名称 | string | |
发布部门 | string | ||
发布日期 | int(1976 02 06) | ||
位置·类(可设定、可更改) | 一个具体位置 | ||
时间·类(可初始设定) | 一个起止时间对 | ||
状态(可阻塞) | waiting:建立了学习活动,确定了时间地点;allocated:为活动安排了学习材料;running:开始学习活动;ended:结束学习活动;cancelled:学习活动结束前被取消 |
3.2.1 PlanningEntry的共性操作
能够返回指定类型的PlanningEntry实现类,Flight Schedule为例:
RUNNING状态在已分配资源之后未启动之前,首先检查是否分配资源(飞机),打印出状态;若已分配资源且状态不为ALLOCATED,则更新航班信息,将状态置为RUNNING,其他同理;考虑没有找到航班的情况。
需要注意的是,只有高铁是可阻塞的、只有活动是可变更地点的、只有高铁是不可变更时间的。
3.2.2 局部共性特征的设计方案
CommonPlanningEntry类实现了PlanningEntry接口中共性方法,包括了状态转换和Getter方法。
方法 | 用途 |
---|---|
public void allocate(PlanningEntry A, String location, String timeslot, String state) | 分配资源 |
public void run(PlanningEntry A, String resource, String type, String seat, String age) | 完成分配后,启动项目 |
public void cancel(PlanningEntry A) | 取消项目 |
public void end(PlanningEntry A) | 结束项目 |
public void block(PlanningEntry A, String location_A, String timeslot_A) | 阻塞项目(高铁) |
public String getName(PlanningEntry A) | getter&setter |
public String getState(PlanningEntry A) |
3.2.3 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)
3个子类型的不同主要在于两方面:Location、TimeSlot、Resource等信息的存储模式和信息的修改。以FlightPlanningEntry为例:
我的存储用数组实现,由于Flight的location由两个,因此用[1][2]分别表示起飞地点和抵达地点;信息修改同理,根据不同计划项信息的修改特点进行设计。分配资源只需修改location、timeslot和state的具体数据
3.3 面向复用的设计:R
资源有多种,因为被设计为一个接口,有3个实现类:Flight、Train和Activity。接口中有3种子类的工厂方法。由于用数组实现,因此在allocated时就已经将项目的resourece输入,以flight为例,
3.4 面向复用的设计:Location
原本打算采用一个List来存储若干的位置,通过PlanningEntry的不同Getter来获取
但采用数组存储后——对Activity只需将location存在[i][2],对Flight只需将出发点存在[i][4]、结束点存在[i][5],对Train只需将location存在[i][2]~[i][4]
3.5 面向复用的设计:Timeslot
Time Slot设计同理location,两点分别代表对应的位置的到达和离开时间。由此设计,可以精确到每个地点的到达和离开时间,可以分别适应有一个地点的活动、两个地点的航班、多个地点的高铁。
由此,3种不同的计划项,通过不同的Getter实现不同的特征。
3.6 面向复用的设计:EntryState及State设计模式
采用State设计模式,把EntryStates设计成一个接口,再用几个类来实现了WAITING、ALLOCATED、RUNNING、BLOCKED、ENDED、CANCELLED几个状态。状态的实现采用静态属性和私有化构造器的办法来节约内存。
这里使用一个SetAndGet方法实现后续设定并获得状态的功能
3.7 面向应用的设计:Board
Column 1 | Column 2 | Column 3 | Column 4 |
---|---|---|---|
显示屏 | 航班 | 抵达屏 | 过去1小时~未来1小时内抵达的航班信息、状态 |
出发屏 | 过去1小时~未来1小时内起飞的航班信息、状态 | ||
高铁 | 抵达屏 | 过去1小时~未来1小时内抵达的高铁信息、状态(需考虑经停车次) | |
出发屏 | 过去1小时~未来1小时内起飞的高铁信息、状态(需考虑经停车次) | ||
活动版 | 会议室预订表 | 当日所有活动以及状态 |
实验指导书中说到,Board是直接面向应用设计的,于是我直接实现了FlightBoard、TrainBoard、CourseBoard三个类。每个Board都有time和location属性来记录这个信息板要展示的时间和地点,以Interator按时间顺序进行排序。
————————————————————————————————
3.8 Board的可视化:外部API的复用
3.9 PlanningEntryCollection的设计
用二维数组实现,以main()选择需要实现的功能
该ADT是PlanningEntry的集合类。
———————————————————————————————
3.10 可复用API设计及Façade设计模式
3.10.1 检测一组计划项之间是否存在位置独占冲突
双层循环遍历。设计思路是对于传入的一组计划项,如果他们当中有位置相同&&位置不可共享&&起止时间有交集的话则是存在独占冲突的,否则没有。
3.10.2 检测一组计划项之间是否存在资源独占冲突
同上,条件变为资源部分是否有冲突。
3.10.3 提取面向特定资源的前序计划项
提取面向特定资源的前序计划项。针对某个资源 r 和使用 r 的某个计划项 e,从一组计划项中找出 e 的前序 f, f 也使用资源 r, f 的执行时间在 e 之前,且在 e 和 f 之间不存在使用资源 r 的其他计划项。若不存在这样的计划项 f,则 返回 null。 如果存在多个这样的 f,返回其中任意一个即可。
对 ROM、学习资 料等不可区分个体的资源,该 API 不适用。
3.11 设计模式应用
3.11.1 Factory Method
设置3个PlanningEntry接口的工厂方法,分别新建1种计划项子类型。以Flight Schedule为例,需要输入Location、TimeSlot和计划项编号3个参数,返回一个FlightSchedule计划项类型:
3.11.2 Iterator
在Board中直接返回一个List Entries的Iterator即可。
public Iterator iterator() {
return entries.iterator();
}
3.11.3 Strategy
在PlanningEntriesAPI中直接设置抽象方法
————————————————————————————————
3.12 应用设计与开发
3.13 基于语法的数据读入
(正则表达式)
3.14 应对面临的新变化
3.14.1 变化1
对于活动、航班、高铁的一个、两个、多个位置管理,我采用数组存贮他们的位置,因此只需获取对应的下标即可查询相应位置。
3.14.2 变化2
高铁的变化在于,若被分配资源后则不能被取消。这个变化可以通过重写cancel()方法,增加判断语句限制前置状态即可。
3.14.3 变化3
学习活动与高铁和航班不同的是,学习活动的时间和地点都是可变化的,这个变化可以通过增加可阻塞的活动名单,该方法代价较小
3.15 Git仓库结构
4 实验进度记录
日期 | 时间段 | 计划任务 | 实际完成情况 |
---|---|---|---|
5.9 | 10小时 | 完成底层代码 | 延期 |
5.10 | 9小时 | 完成底层代码 | 完成 |
5.14~5.16 | 20小时+ | 完成客户的 | 完成 |
5.17 | 2小时 | 完善报告 | 完成 |
5 实验过程中遇到的困难与解决途径
-
正则表达式不会使用
参与群聊、上网查阅资料
-
不理解多种设计模式的概念
重看网课