欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

软件构造Lab3

程序员文章站 2024-02-09 16:58:34
...

2021年春季学期
计算学部《软件构造》课程

Lab 3实验报告

姓名 聂兆彦
学号 1180300429
班号 1803401
电子邮件 [email protected]
手机号码 15504871876

目录

2 实验环境配置
3 实验过程
3.1 待开发的三个应用场景
3.2 面向可复用性和可维护性的设计:IntervalSet
3.2.1 IntervalSet的共性操作
3.2.2 局部共性特征的设计方案
3.2.3 面向各应用的IntervalSet子类型设计(个性化特征的设计方案)
3.3 面向可复用性和可维护性的设计:MultiIntervalSet
3.3.1 MultiIntervalSet的共性操作
3.3.2 局部共性特征的设计方案
3.3.3 面向各应用的MultiIntervalSet子类型设计(个性化特征的设计方案)
3.4 面向复用的设计:L
3.5 可复用API设计
3.5.1 计算相似度
3.5.2 计算时间冲突比例
3.5.3 计算空闲时间比例
3.6 应用设计与开发
3.6.1 排班管理系统
3.6.2 操作系统的进程调度管理系统
3.6.3 课表管理系统
3.7 基于语法的数据读入
3.8 应对面临的新变化
3.8.1 变化1
3.8.2 变化2
3.9 Git仓库结构
4 实验进度记录
5 实验过程中遇到的困难与解决途径
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
6.2 针对以下方面的感受

1实验目标概述
编写具有可复用性和可维护性的软件,主要使用以下软件构造技术:
子类型、泛型、多态、重写、重载
继承、代理、组合
语法驱动的编程、正则表达式
API 设计、API 复用
本次实验给定了三个具体应用(值班表管理、操作系统进程调度管理、大学课表管理),学生不是直接针对每个应用分别编程实现,而是通过 ADT 和泛型等抽象技术,开发一套可复用的 ADT 及其实现,充分考虑这些应用之间的相似性和差异性,使 ADT 有更大程度的复用(可复用性)和更容易面向各种变化(可维护性)。
2实验环境配置
简要陈述你配置本次实验所需环境的过程,必要时可以给出屏幕截图。
特别是要记录配置过程中遇到的问题和困难,以及如何解决的。
配置过程中出现了GitHub无法重命名的问题,最后等了几天就没有这个问题了。

在这里给出你的GitHub Lab3仓库的URL地址(HIT-Lab3-学号)。
https://github.com/ComputerScienceHIT/HIT-Lab3-1180300429.git
实验过程
请仔细对照实验手册,针对每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
2.1待开发的三个应用场景
简要介绍三个应用。
分析三个应用场景的异同,理解需求:它们在哪些方面有共性、哪些方面有差异。
本次设计的目标为三个应用:
值班表管理:一个单位有 n 个员工,在某个时间段内(例如寒假 1 月 10 日到 3 月 6 日期间),每天只能安排唯一一个员工在单位值班,且不能出现某天无人值班的情况;每个员工若被安排值班 m 天(m>1),那么需要安排在连续的 m 天内。值班表内需要记录员工的名字、职位、手机号码,以便于外界联系值班员。
操作系统进程调度管理:考虑计算机上有一个单核CPU,多个进程被操作系统创建出来,它们被调度在 CPU 上执行,由操作系统决定在各个时段内执行哪个线程。操作系统可挂起某个正在执行的进程,在后续时刻可以恢复执行被挂起的进程。可知:每个时间只能有一个进程在执行,其他进程处于休眠状态;一个进程的执行被分为多个时间段;在特定时刻,CPU 可以“闲置”,意即操作系统没有调度执行任何进程;操作系统对进程的调度无规律,可看作是随机调度。
大学课表管理:针对某个班级,假设其各周的课表都是完全一样的(意即同样的课程安排将以“周”为单位进行周期性的重复,直到学期结束);一门课程每周可以出现 1 次,也可以安排多次(例如每周一和周三的“软件构造”)且由同一位教师承担并在同样的教室进行;允许课表中有空白时间段(未安排任何课程);考虑到不同学生的选课情况不同,同一个时间段内可以安排不同的课程(例如周一上午 3-4 节的“计算方法”和“软件构造”);一位教师也可以承担课表中的多门课程。
分析三个应用场景的异同:三个应用场景都是有关时间段集合的操作,都为“在特定时间段进行的特定任务”的抽象,都有着插入时间段等相同的操作。
值班表管理和操作系统进程调度管理中时间段集合不可以有重叠,而大学课表管理中的时间可以有重叠。值班表管理中的一个label只能对应一个时间段,而操作系统进程调度管理和大学课表管理中的一个label可以对应多个时间段。值班表管理和操作系统进程调度管理中时间段集合没有重复性,而大学课表管理中的时间段集合有一定的重复性。值班表管理中不可以存在时间段的空缺,而操作系统进程调度管理和大学课表管理可以存在时间段的空缺。而且三个应用场景的label各不相同,值班表管理为员工,操作系统进程调度管理为进程,大学课表管理为课程。

2.2面向可复用性和可维护性的设计:IntervalSet
该节是本实验的核心部分。
2.2.1IntervalSet的共性操作
接口 IntervalSet的共性接口方法:
创建一个空对象:empty() 静态方法
在当前对象中插入新的时间段和标签:void insert(long start,
long end, L label) 实例方法
获得当前对象中的标签集合:Set labels() 实例方法
从当前对象中移除某个标签所关联的时间段:boolean remove(L
label) 实例方法
返回某个标签对应的时间段的开始时间:long start (L label) 实例方法
返回某个标签对应的时间段的结束时间:long end (L label) 实例方法
返回某个label的所有时间段:List

 在这之中NonOverlapIntervalSet重写了insert方法,在插入时间段的时候判断该时间段的插入是否会造成重叠,若会造成重叠,在进行提示,退出程序。否则,调用原来的insert方法。
 
 在这之中NoBlankIntervalSet重写了checkNoBlank方法,调用该方法时会返回一个时间段的集合,根据该集合,客户端可以判断排班表中是否有有空白和空白所在的位置。

2.3面向可复用性和可维护性的设计:MultiIntervalSet
2.3.1MultiIntervalSet的共性操作
将 MultiIntervalSet实现为接口,实现一个具体类,其名字应为
CommonMultiIntervalSet。在其 rep 中,使用 IntervalSet作为其 rep 的一部分,复用 IntervalSet及其实现类中已经实现的功能。
MultiIntervalSet所提供的方法包括:
创建一个空对象:empty()或不带任何参数的构造函数 静态方法
创建一个非空对象:构造函数 MultiIntervalSet(IntervalSet initial),利用 initial 中包含的数据创建非空对象 静态方法
在当前对象中插入新的时间段和标签:void insert(long start, long end, L label) 实例方法
获得当前对象中的标签集合:Set labels() 实例方法
从当前对象中移除某个标签所关联的所有时间段:boolean remove(L label) 实例方法
从 当 前 对 象 中 获 取 与 某 个 标 签 所 关 联 的 所 有 时 间 段IntervalSet intervals(L label); 实例方法:
计算任意一个起始时间long onestart();实例方法
计算任意一个终止时间long onesend();实例方法
2.3.2局部共性特征的设计方案
根据方案5的方法,我在MultiIntervalSet的三个维度(是否允许有空白,是否可以重叠,是否有周期)建立了三个接口NonOverlapMultiIntervalSet,NoBlankMultiIntervalSet,NonPeriodicMultiIntervalSet。然后设计NonOverlapMultiIntervalSetImpl,NoBlankMultiIntervalSetImpl,NonPeriodicMultiIntervalSetImpl来实现三个不同的维度。

2.3.3面向各应用的MultiIntervalSet子类型设计(个性化特征的设计方案)
在应用设计中,通过我上面的分析可以得到,操作系统进程调度管理和大学课表管理是MultiIntervalSet。操作系统进程调度管理不可以重叠的。故操作系统进程调度管理的接口需要继承NonMultiOverlapIntervalSet。

在这之中NonOverMultilapIntervalSet重写了insert方法,在插入时间段的时候判断该时间段的插入是否会造成重叠,若会造成重叠,在进行提示,退出程序。否则,调用原来的insert方法。

 大学课表管理是MultiIntervalSet。大学课表管理是重复的。故大学课表管理的接口需要继承NonPeriodicMultiIntervalSet。

在这之中NonPeriodicMultiIntervalSet重写了insert方法,在插入时间段的时候会根据重复的情况进行多次插入。

2.4面向复用的设计:L
L是针对时间段的标签,在不同的应用环境中有不同的情况。对三个应用来说,其 L 分别应为“员工”(Employee)、“进程”(Process)、
“课程”(Course),所需关注的属性分别为:
Employee:姓名、职务、手机号码
Process:进程 ID、进程名称、最短执行时间、最长执行时间
Course:课程 ID、课程名称、教师名字、地点
2.5可复用API设计
2.5.1计算相似度
计算两个 MultiIntervalSet 对象的相似度:double Similarity(MultiIntervalSet s1, MultiInterval Set s2)
具体计算方法:按照时间轴从早到晚的次序,针对同一个时间段内两个对象里的 interval,若它们标注的 label 等价,则二者相似度为 1,否则为 0;若同一时间段内只有一个对象有 interval 或二者都没有,则相似度为 0。将各interval 的相似度与 interval 的长度相乘后求和,除以总长度,即得到二者的整体相似度。

2.5.2计算时间冲突比例
发现一个 IntervalSet或 MultiIntervalSet对象中的时间冲突比例。double calcConflictRatio(IntervalSet set)
double calcConflictRatio(MultiIntervalSet set)
具体计算方法:遍历每一个IntervalSet或 MultiIntervalSet中的每一个时间段,针对每一个时间段,对每一个与其不同标签的时间段根据两个时间段的起始点与终止点的相对位置判断是否有重叠即冲突以及在时间轴上产生冲突的长度 ,对冲突长度进行累加,直到遍历完成。最后将累加后的冲突长度除以总长度再除以2。得到时间冲突比例。

2.5.3计算空闲时间比例
计算一个 IntervalSet或 MultiIntervalSet对象中的空闲时间比例
double calcFreeTimeRatio(IntervalSet set)
double calcFreeTimeRatio(MultiIntervalSet set)
具体计算方法:先设置一个起点(所有时间段的最小起始点)与一个终点(所有时间段的最大终止点),遍历所有IntervalSet或 MultiIntervalSet对象中的时间段,寻找到空闲块的起点,再遍历所有IntervalSet或 MultiIntervalSet对象中的时间段,寻找到对应空闲块的终点,利用空闲块的起点与终点计算空闲时间并进行累加;重复上述的两次遍历直到到达终点。将累加的空闲时间除以总时间得到空闲时间比例。

2.6应用设计与开发
利用上述设计和实现的ADT,实现手册里要求的各项功能。
2.6.1排班管理系统
静态方法创建空排班系统IDutyRoster empty(NonOverlapIntervalSet nois, NoBlankIntervalSet nbis )
静态方法设置员工 Employee setEmployee(String name,String job,String num)
将员工添加到排班系统中void addemploy(Employee label);
将员工从排班系统中删除void removeEmployee(Employee label);
为某一位员工添加一天的值班void insertaday(int year, int month, int day,Employee label);
为某一位员工添加一段时间的值班void insertperiod(int year1, int month1, int day1,int year2,int month2,int day2,Employee label);
检查排班是否已满若未满,则展示给用户哪些时间段未安排、未安排的时间段占总时间段的比例。void CheckNoBlank()
创建空的排班系统:

设置起始终止时间并设置一系列员工将员工加入到排班系统中

分配值班并可视化

检查排班是否已满,发现未满,得到那些时间有空闲,那些员工有空闲和空闲比例。

将其中一个员工删除,并查看删除后的排班表

发现该员工以及在排班表中,将该员工所有的相关信息删除

观察到删除该员工后的排班表,该员工及相关信息已经删除。

再将一个未分配值班的员工分配值班

观察到添加后的排班表,该员工被分配到了正确的位置

观察到了新的检查排班是否已满,发现未满,得到那些时间有空闲,那些员工有空闲和空闲比例的信息。

开启自动排班,打印自动排班后的排班表及空闲信息

观察到自动排班后的排班表

观察到自动排班后没有空闲时间,符合预期效果

2.6.2操作系统的进程调度管理系统
静态方法创建一个新的操作系统的进程调度管理表IProcessSchedule empty(NonOverlapMultiIntervalSet nois)
静态方法创建一个新进程Process setProcess(String ID,String name,long maxtime,long mintime)
将进程加入到管理系统中void addeprocess(Process label)
启动模拟调度void Simulationscheduling()
可视化展示进程调度结果void print()
创建一个空的进程调度管理系统

创建若干个进程并将其加入到进程调度管理系统中

调用启动模拟调度,并观察调度结果

调度结果1

再调度一次,观察到两次结果不同,符合随机调度

可视化展示进程调度结果

可以观察到任意时刻进行的进程与之前的所有进程

2.6.3课表管理系统
静态方法创建一个新的课表管理系统,ICourseSchedule empty(
NonPeriodicMultiIntervalSet npis,LocalDate timestart)
在课表管理系统中加入的课程void addcourse(Course e)
在特定时间添加特定的课程void insert(String ID,String week,String time)
查看本学期内任意一天的课表结果void print(int year,int month,int day)
查看当前每周的空闲时间比例void CalcFreeTime()
查看哪些课程没安排void checkcourse()
查看重复时间比例void calcConflictTime()
设置学期开始的时间,创建一个新的课表管理系统

创建一系列课程,并将其插入到课表管理系统中

先分配一次课,检查哪些课没有安排及安排情况

观察到未满的课程信息及目前已经安排的课程信息

再插入一些课程,打印第一天的课程信息

观察到当天的课程情况

查看哪些课程没安排和查看重复时间比例

2.7基于语法的数据读入
修改“排班管理”应用以扩展该功能。
加入新功能:void extendfunction(String f);
利用Scanner读取文件

利用判断读取的文件格式是否与上述正则表达式匹配,若不合法则报错退出。

若合法则开始构造排班表,根据文件读入的信息进行员工的构造,起始日期与终止日期的构造,并进行排班。并在这个过程中检查员工名字重复,排班员工未定义等问题。

2.8应对面临的新变化
2.8.1变化1
评估之前的设计是否可应对变化、代价如何
如何修改设计以应对变化
由于利用了通过接口组合实现局部共性特征的复用的方法,这个新的变化很好更改,代价也十分小。主要是将继承的所有的IntervalSet改成MultiIntervalSet,将所有的每个接口NonOverlapIntervalSet改成NonOverlapMultiIntervalSet,所有的NoBlankIntervalSet改成NoBlankMultiIntervalSet。文件前面的import的东西改一下,还有就是对为数不多的遍历方法进行调整

将原来的运行代码拿来测试发现结果与修改之前的一样
并且测试了一个员工插入多个时间段的情况,发现更改后可以一个员工插入多个时间段。

2.8.2变化2
评估之前的设计是否可应对变化、代价如何
如何修改设计以应对变化
本来是在CourseMultiIntervalSet中加一个NonOverlapMultiIntervalSet的接口再调用NonOverlapMultiIntervalSetImpl的重写就可以,但由于我的设计上的一些问题,我的NonPeriodicMultiIntervalSetImpl与NonOverlapMultiIntervalSet接口都重写的insert函数,两个一起调用会产生冲突,造成结果错误,于是做了一些的小调整解决了这个问题:
在CourseMultiIntervalSet中的insert函数

将NonPeriodicMultiIntervalSetImpl中的insert改成:

这样就可以根据NonOverlapMultiIntervalSet中的insert的冲突与否选择是否进行周期性插入,从而解决了这个问题。
我们对原来的命令再进行运行,发现与以前不同的是,更改后不能够出现重叠的情况,并且由于不能重叠,其重复时间比例永远为0。其他操作没有影响。