2020年春季学期
计算机学院《软件构造》课程
Lab 3实验报告
目录
1 实验目标概述 1
2 实验环境配置 1
3 实验过程 1
3.1 待开发的三个应用场景 1
3.2 面向可复用性和可维护性的设计:PlanningEntry 1
3.2.1 PlanningEntry的共性操作 1
3.2.2 局部共性特征的设计方案 2
3.2.3 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案) 2
3.3 面向复用的设计:R 2
3.4 面向复用的设计:Location 2
3.5 面向复用的设计:Timeslot 2
3.6 面向复用的设计:EntryState及State设计模式 2
3.7 面向应用的设计:Board 2
3.8 Board的可视化:外部API的复用 2
3.9 PlanningEntryCollection的设计 2
3.10 可复用API设计及Façade设计模式 2
3.10.1 检测一组计划项之间是否存在位置独占冲突 2
3.10.2 检测一组计划项之间是否存在资源独占冲突 2
3.10.3 提取面向特定资源的前序计划项 2
3.11 设计模式应用 2
3.11.1 Factory Method 3
3.11.2 Iterator 3
3.11.3 Strategy 3
3.12 应用设计与开发 3
3.12.1 航班应用 3
3.12.2 高铁应用 3
3.12.3 进程应用 3
3.12.4 课表应用 3
3.12.5 学习活动应用 3
3.13 基于语法的数据读入 3
3.14 应对面临的新变化 3
3.14.1 变化1 3
3.14.2 变化2 4
3.14.3 变化3 4
3.15 Git仓库结构 4
4 实验进度记录 4
5 实验过程中遇到的困难与解决途径 4
6 实验过程中收获的经验、教训、感想 5
6.1 实验过程中收获的经验和教训 5
6.2 针对以下方面的感受 5
1 实验目标概述
本次实验覆盖课程第 3、4、5 章的内容,目标是编写具有可复用性和可维护 性的软件,主要使用以下软件构造技术:
子类型、泛型、多态、重写、重载
继承、代理、组合 常见的 OO 设计模式
语法驱动的编程、正则表达式
基于状态的编程
API 设计、API 复用
本次实验给定了五个具体应用(高铁车次管理、航班管理、操作系统进程管 理、大学课表管理、学习活动日程管理),学生不是直接针对五个应用分别编程 实现,而是通过 ADT 和泛型等抽象技术,开发一套可复用的 ADT 及其实现,充 分考虑这些应用之间的相似性和差异性,使 ADT 有更大程度的复用(可复用性) 和更容易面向各种变化(可维护性)。。
2 实验环境配置
简要陈述你配置本次实验所需环境的过程,必要时可以给出屏幕截图。
特别是要记录配置过程中遇到的问题和困难,以及如何解决的。
在这里给出你的GitHub Lab3仓库的URL地址(Lab3-学号)。
https://github.com/ComputerScienceHIT/Lab3-1180300503.git
3 实验过程
请仔细对照实验手册,针对每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1 待开发的三个应用场景
我选择的三个应用场景:
航班管理
高铁车次管理
学习日程管理
这三个场景的异同点:
位置的数量:分别为1个、2个和多个
仅有学习日程的位置可更改
航班为单个资源,高铁为有序多个资源,学习日程为无序多个资源
仅有高铁车次可阻塞
时间均在创建时设定
3.2 面向可复用性和可维护性的设计:PlanningEntry
该节是本实验的核心部分。
3.2.1 PlanningEntry的共性操作
其中包括:
1.活动的创建
2.计划项的状态的设置
3.计划项名称的设置
4.为计划项分配资源
5.判断计划项是否可以被取消(阻塞)
3.2.2 局部共性特征的设计方案
所有的局部共性操作均放在PlanningEntry接口中,在CommonPlanningEntry加以实现,比如start,end,cancel之类的状态改变函数。在三个应用中,时间,资源,位置的设置有很大的区别,需要在各自的子类中加以实现。
3.2.3 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)
航班计划项
航班计划项中包含资源的设置,时间的设置,位置的设置,需要设置日期,在FlightEntry中继承CommonPlanningEntry,其余的操作在各自的app函数中加以实现
高铁计划项
与航班类似,区别就是有经停站的影响,所以位置和时间都设置为了List列表,由于单个资源为车厢,而不是一整个高铁,所以资源项也为List列表,代表车厢的集合。
课程计划项
课程计划项也与航班计划项类似,但是位置只有一个。
3.3 面向复用的设计:R
飞机:
包括飞机的编号,类型,满员数,机龄等,除了Getter函数之外,含包括判断是否两架飞机相同的判断函数。
高铁车厢:
包括车厢的编号,类型,生产日期,满员数,除了各自的Getter函数之外,还包括判断两个车厢是否为同一个车厢的判断函数。
教师:
包含教师的ID,姓名,性别,职称,均采用String类型,除了Getter函数之外,还包括判断是否两个教师为同一个教师的判断函数。
3.4 面向复用的设计:Location
根据不同的计划项,位置信息包括位置的名称和是否可以共享,除了getter函数之外,还包括判断两个位置是否相同的判断函数。
3.5 面向复用的设计:Timeslot
有不同的构造函数,可以添加一个时间(比如出发和到达),可以添加两个时间(比如经停站中,到达和出发时间),另外,Timeslot中含有几个static函数,来判断时间是否符合规范,判断两个时间的先后顺序,判断时间与日期是否相同等
3.6 面向复用的设计:EntryState及State设计模式
采用State模式,state是一个接口,多种不同的状态继承该接口,在应用中直接调用子类来实现多种状态的转换。
3.7 面向应用的设计:Board
Borad不要求复用,所以只需在各自的子类中实现即可。不同的Board类型大致一样,输出符合要求的计划项。并以表格的形式显现出来。
3.8 Board的可视化:外部API的复用
3.9 PlanningEntryCollection的设计
该ADT是PlanningEntry的集合类。
该ADT未显式的表达出来,在各自的app中通过一个List集合将所有的计划项加入进去,通过确定的输出可以进行表达。
3.10 可复用API设计及Façade设计模式
PlanningEntryAPIs中有所有函数的子类,通过Façade设计模式,在调用方法的过程中直接调用PlanningEntryAPIs中的方法实现对底层函数的调用。
3.10.1 检测一组计划项之间是否存在位置独占冲突
基本的思想是输入确定的信息,根据给定的时间与计划项,逐个遍历计划项,若是俩个计划项占用位置相同并且时间存在重叠,则产生了位置冲突。
3.10.2 检测一组计划项之间是否存在资源独占冲突
与处理位置冲突相似,基本的思想是输入确定的信息,根据给定的时间与计划项,逐个遍历计划项,若是俩个计划项占用资源相同并且时间存在重叠,则产生了资源冲突。
3.10.3 提取面向特定资源的前序计划项
在输入必要信息后,遍历计划项,如果存在计划项在指定计划项之前(结束时间早于指定计划项的开始时间),并且所用资源相同,那么更新当前计划项,在找到更符合要求的计划项后,继续更新计划项,直到遍历完为止。
3.11 设计模式应用
请分小节介绍每种设计模式在你的ADT和应用设计中的具体应用。
3.11.1 Factory Method
在PlanningEntry以及其子类中运用Factory Method,在今后的app中,不必直接new一个子类,而是通过PlanningEntry中的方法进行初始化。
3.11.2 Iterator
在Board类中,通过迭代器模式对计划项的集合逐个输出。
3.11.3 Strategy
采用 Strategy模式,对寻找资源的前序计划项设计两种算法,并逐个应用,有良好的效果。
3.12 应用设计与开发
利用上述设计和实现的ADT,实现手册里要求的各项功能。
只需保留你选定的三个应用即可。
3.12.1 航班应用
一共有13个具体应用,列出前三个应用。
管理资源
管理位置
新增计划项
3.12.2 高铁应用
一共有14个具体应用,列出前三个应用。
管理资源
管理位置
新增计划项
3.12.3 课表应用
一共有13个具体应用,列出前三个应用。
管理资源
管理位置
新增计划项
3.13 基于语法的数据读入
修改“航班”应用以扩展该功能。
3.14 应对面临的新变化
只考虑你选定的三个应用的变化即可。
3.14.1 变化1
将每个FlightEntry中的位置增加,存储两个或三个位置,这样可以较为简单的解决经停站问题。
3.14.2 变化2
判断是否取消时删除分配状态即可。较为简单。
3.14.3 变化3
将每个课程计划项的老师资源设为一个List列表,存储多个老师,当比较课程老师是否一致时,取List中的第一个教师(主要教师)进行比较。
3.15 Git仓库结构
请在完成全部实验要求之后,利用Git log指令或Git图形化客户端或GitHub上项目仓库的Insight页面,给出你的仓库到目前为止的Object Graph,尤其是区分清楚314change分支和master分支所指向的位置。
4 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
日期 时间段 计划任务 实际完成情况
2020-05-01 上午 阅读实验指导书 基本完成
2020-05-03 一整天 PlanningEntry和航班计划项 完成60%
2020-05-04 下午 未完成的航班计划项 基本完成
2020-05-06 上午,晚上 完成高铁计划项 基本完成
2020-05-10 上午,晚上 完成课程计划项 基本完成
2020-05-12 晚上 进行314change的完成 基本完成
2020-05-15 下午 编写实验报告 完成50%
2020-05-17 下午 编写实验报告 基本完成
5 实验过程中遇到的困难与解决途径
遇到的难点 解决途径
实验中各种设计模式不会运用
反复观看老师的教学视频,在网上寻找学习资源
基于语法的输入不太会
询问同学,寻求同学的帮助
实验的整体构架思路不清
参考了同学的思路,并且根据自己的想法加以改变
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
6.2 针对以下方面的感受
(1) 重新思考Lab2中的问题:面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?本实验设计的ADT在五个不同的应用场景下使用,你是否体会到复用的好处?
面向ADT编程更加复杂,复用的确可以大量节省代码量!!
(2) 重新思考Lab2中的问题:为ADT撰写复杂的specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后的编程中坚持这么做?
减少输入带来的错误,使输入更加规范。也使自己更加了解各个ADT的具体应用。在今后的编程中要坚持这个好习惯。
(3) 之前你将别人提供的API用于自己的程序开发中,本次实验你尝试着开发给别人使用的API,是否能够体会到其中的难处和乐趣?
难度自我感觉很大,起初设计思路不明确,所以花费了大量时间,但是完成以后,在运用方面更加得心应手,运用更熟练。
(4) 在编程中使用设计模式,增加了很多类,但在复用和可维护性方面带来了收益。你如何看待设计模式?
虽然设计模式增加了很多类,但是对于今后代码的修改和维护起着十分巨大的作用,所以设计模式的应用必不可少。
(5) 你之前在使用其他软件时,应该体会过输入各种命令向系统发出指令。本次实验你开发了一个解析器,使用语法和正则表达式去解析输入文件并据此构造对象。你对语法驱动编程有何感受?
开始不太明白怎么做,后来询问同学之后有了进一步了解。自我感觉语法驱动编程比较抽象,并且麻烦。
(6) Lab1和Lab2的大部分工作都不是从0开始,而是基于他人给出的设计方案和初始代码。本次实验是你完全从0开始进行ADT的设计并用OOP实现,经过五周之后,你感觉“设计ADT”的难度主要体现在哪些地方?你是如何克服的?
该实验难度最大的地方我认为是整体思路的构建,其实思路出来以后,编程并不是特别难,但是我认为大部分人一开始就死在了思路上面,有可能我自己的思路也是不正确的,这是最令人恐慌的,没有正确的模板,一切从0开始,对于我是一个极大的挑战。
(7) “抽象”是计算机科学的核心概念之一,也是ADT和OOP的精髓所在。本实验的五个应用既不能完全抽象为同一个ADT,也不是完全个性化,如何利用“接口、抽象类、类”三层体系以及接口的组合、类的继承、设计模式等技术完成最大程度的抽象和复用,你有什么经验教训?
要灵活使用接口和抽象函数,可以复用的尽量要复用,处理好接口,抽象函数与具体函数之间的关系,最大程度上既减少代码量又实现代码的功能。
(8) 关于本实验的工作量、难度、deadline。
工作量巨大,难度比较难,ddl控制的很合理。
(9) 到目前为止你对《软件构造》课程的评价。
整体来说很好,但是个别方面需要反复观看老师的视频,希望老师以后可以讲清晰一些。