目录
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 可复用API设计及Façade设计模式 2
3.9.1 检测一组计划项之间是否存在位置独占冲突 2
3.9.2 检测一组计划项之间是否存在资源独占冲突 2
3.9.3 提取面向特定资源的前序计划项 2
3.10 设计模式应用 2
3.10.1 Factory Method 3
3.10.2 Iterator 3
3.10.3 Strategy 3
3.11 应用设计与开发 3
3.11.1 航班应用 3
3.11.2 高铁应用 3
3.11.3 进程应用 3
3.11.4 课表应用 3
3.11.5 学习活动应用 3
3.12 基于语法的数据读入 3
3.13 应对面临的新变化 3
3.13.1 变化1 3
3.13.2 变化2 4
3.13.3 变化3 4
3.14 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
3 实验过程
请仔细对照实验手册,针对每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1 待开发的三个应用场景
选定应用:航班,高铁,课程
相同点与不同点如下
3.2 面向可复用性和可维护性的设计:PlanningEntry
该节是本实验的核心部分。
3.2.1 PlanningEntry的共性操作
共性操作:都拥有计划项名字,计划项状态,地点,时间和资源,因此,我将地点和时间设置为集合类型,方便添加地点和时间,然后在每个类中分别用不同方法添加地点和时间,完成相应操作。同时,为了方便对所有内容进行时间升序排列,上层集合使用treeset集合,需要在PlanningEntry中完善判定函数,使得treeset能够正确按照时间升序将计划项放入集合中
3.2.2 局部共性特征的设计方案
局部共性操作:共性操作有:初始化计划项,设置/删除位置/时间/资源,改变计划项状态,以及获取计划项的内容,最后是对compareTo函数的完善
3.2.3 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)
对于航班和课程,只需要完成其获取详细信息的方法即可。对于列车,除了需要完成获取详细信息的方法,还需要增加改变状态为‘blocked’的方法
3.3 面向复用的设计:R
因为计划项中存在大量相同之处,具体使用的资源不同,因此使用R代表具体使用的资源,使得三者可以统一起来,方便复用
3.4 面向复用的设计:Location
我直接用List表示地点集合,但是在输入参数时限定航班只能输入两个地点,课程只能输入一个地点
3.5 面向复用的设计:Timeslot
我直接用List表示时间集合,但是在输入参数时限定航班和课程只能输入两个时间,航班时间数和地点数相同,课程在添加了地点时可以添加两个时间,列车的时间数是地点数的2倍-2个
3.6 面向复用的设计:EntryState及State设计模式
state作为判断状态的条件,在上层输入的时候进行判断。因为三个方法的state判断条件不同,因此我选择分别实现state的判断,将共同点放入PlanningEtry中,同时保证传入修改状态的参数一定是正确的,符合实际情况的
3.7 面向应用的设计:Board
实现具体app的内容,我选择分别实现。因为底层类设计完善,在做好航班管理app后,大部分代码可以通过复制粘贴完成,只需要更改少部分代码即可复用在列车和课程管理上
3.8 Board的可视化:外部API的复用
使用swing程序包完成可视化操作,通过多级菜单完成对每个功能的实现
3.9 可复用API设计及Façade设计模式
设计AppStart可视化界面,通过用户的选择来创建不同的管理app
结果如下
3.9.1 检测一组计划项之间是否存在位置独占冲突
作为课程独有的“教室”,存在是否被占据的可能。对于在同一个地点上课的课程,如果时间发生冲突,说明存在冲突,返回false
时间冲突判断方法:t1,t2为新建课程的起止时间,t3,t4为原有课程的起止时间。如果t1<=t3<t2或者t3<=t1<t4,说明时间上有冲突
3.9.2 检测一组计划项之间是否存在资源独占冲突
资源独占冲突与位置独占冲突同理,将所有资源相同的计划项的时间列出,获取其使用时间,与将要新建或者修改的计划项的时间进行对比。如果有重合时间段说明时间发生冲突。
3.9.3 提取面向特定资源的前序计划项
根据输入的计划项获取其使用的资源。因为使用的是treeset集合,对所有计划项的时间进行了升序排列,因此只需要遍历在该计划项前面的所有计划项,最后一个拥有同样资源的计划项即为其前序计划项。
3.10 设计模式应用
请分小节介绍每种设计模式在你的ADT和应用设计中的具体应用。
3.10.1 Factory Method
新建工厂类,用于生成不同的计划项。
3.10.2 Iterator
因为使用了treeset并重写了compareTo函数,使得在集合中的元素自然按照时间升序排列,未使用Iterator
3.10.3 Strategy
将三个不同app通过按钮包装起来,按下不同按钮调用不同app实现不同功能
3.11 应用设计与开发
功能全部实现,以按钮+弹窗形式实现对内容的操作
3.11.1 航班应用
如下
3.11.2 高铁应用
如下
3.11.3 课表应用
如下
3.12 基于语法的数据读入
使用到的正则表达式:
将所有内容分成行,并根据开头将其赋值到对应位置,创建计划项,结果如下
3.13 应对面临的新变化
3.13.1 变化1
因为我创建的航班对于时间和地点都是用与列车相同的Arraylist来进行存储,因此,若要支持中转,只需要将Trains中的方法搬过来即可,无需大变动
3.13.2 变化2
如果高铁分配车厢后不能取消,只需要将app中取消这个功能的按钮,并将Trains类中的删除资源方法删除即可,无需大变动。
3.13.3 变化3
如果课程需要多个老师上课,只需要将高铁的“多节车厢”资源模式搬过来即可,同时将列车计划项对资源的操作搬到课程中即可,无需大变动。
3.14 Git仓库结构
无法登录Github
请在完成全部实验要求之后,利用Git log指令或Git图形化客户端或GitHub上项目仓库的Insight页面,给出你的仓库到目前为止的Object Graph,尤其是区分清楚314change分支和master分支所指向的位置。
4 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
日期 时间段 计划任务 实际完成情况
5.4~5.5 两整天20小时 完成底层代码 如期完成
5.8~5.9 两整天20小时 完成客户端 如期完成
5.10 一整天 完成报告与剩下细碎的要求 如期完成
5 实验过程中遇到的困难与解决途径
遇到的难点 解决途径
对于swing程序包的不理解
上网查资料解决
对于正则表达式的不熟悉
询问同学,查询相关资料解决
对于设计模式的不理解
重看网课,加深印象,查询相关资料
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
6.2 针对以下方面的感受
(1) 重新思考Lab2中的问题:面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?本实验设计的ADT在五个不同的应用场景下使用,你是否体会到复用的好处?
通过复用可以极大减小代码量和任务量,无需繁琐操作即可实现复杂的功能
(2) 重新思考Lab2中的问题:为ADT撰写复杂的specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后的编程中坚持这么做?
在后续编写程序时可以很快弄明白这段代码该如何使用,避免不必要的麻烦
(3) 之前你将别人提供的API用于自己的程序开发中,本次实验你尝试着开发给别人使用的API,是否能够体会到其中的难处和乐趣?
难是难,乐趣并存。写完代码有种“如释负重”的感觉
(4) 在编程中使用设计模式,增加了很多类,但在复用和可维护性方面带来了收益。你如何看待设计模式?
设计模式有利有弊。方便调用的同时,增加寻找代码的时间。(可能是我的结构不够好)
(5) 你之前在使用其他软件时,应该体会过输入各种命令向系统发出指令。本次实验你开发了一个解析器,使用语法和正则表达式去解析输入文件并据此构造对象。你对语法驱动编程有何感受?
之前有写过这样的实验,可以根据格式来匹配大量数据,可以减小工作量
(6) Lab1和Lab2的大部分工作都不是从0开始,而是基于他人给出的设计方案和初始代码。本次实验是你完全从0开始进行ADT的设计并用OOP实现,经过五周之后,你感觉“设计ADT”的难度主要体现在哪些地方?你是如何克服的?
主要体现在“从0开始”。需要一点一点从最底层开始写代码,繁重的工作任务是难度之一。还有不计其数的小细节需要考虑,以及需要大片大片的完整空余时间来进行编程,确实耗费不少心血。
(7) “抽象”是计算机科学的核心概念之一,也是ADT和OOP的精髓所在。本实验的五个应用既不能完全抽象为同一个ADT,也不是完全个性化,如何利用“接口、抽象类、类”三层体系以及接口的组合、类的继承、设计模式等技术完成最大程度的抽象和复用,你有什么经验教训?
我对于抽象和复用的理解还不是特别深刻,还需要在后续的学习中继续巩固拓展。
(8) 关于本实验的工作量、难度、deadline。
(9) 工作量较大,难度较大,deadline适中,总体感觉具有挑战性,完成后的满足感也比较强。
(10) 到目前为止你对《软件构造》课程的评价。
我认为课程内容充实丰满,实验有难度,而且具有较高强度,为以后的编程生涯积累经验。