软件构造实验3相关

软件构造实验三过程及思考

1 实验目标概述
本次实验目标是编写具有可复用性和可维护性的软件,主要使用以下软件构造技术:

  1. 子类型、泛型、多态、重写、重载
  2. 继承、代理、组合
  3. 语法驱动的编程、正则表达式
  4. API 设计、API 复用
    2 实验环境配置
    3 实验过程
    请仔细对照实验手册,针对每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
    3.1 待开发的三个应用场景
    简要介绍三个应用。
    分析三个应用场景的异同,理解需求:它们在哪些方面有共性、哪些方面有差异。
    值班管理 :不能有空余时间,即某天无人值班;给某人排版必须在连续时间内,不能分开,即只能与一个时间段关联
    操作系统进程调度管理:每个时间段内只能有一个正在执行的进程;一个进程可以被分割在多个时间段执行,及可以与多个事件段关联。
    大学课表管理:每个时间段内可以有不同的课程安排;每种课程也可以被安排在多个时间段内(只要小于等于每周课时上限即可),即每种课程也可以和多个时间段关联。

3.2 面向可复用性和可维护性的设计:IntervalSet
该节是本实验的核心部分。
3.2.1 IntervalSet的共性操作
对时间段进行操作,需要创建一个空的时间段,然后向时间段中插入时间安排,根据时间安排的某个类,可以删除时间段中的某个时间安排。IntervalSet还需要能够返回在这条时间线上所有的标签;需返回某个标签对应的时间段的开始时间和结束时间。该接口的方法有:
(1)创建一个空对象:empty()
(2)在当前对象中插入新的时间段和标签:void insert(long start, long end, L label)。参数分别为事件的开始时间,结束时间,标签。如果新插入的标签已经存在,或欲插入的时间段已经被占用,则抛出异常。
(3)获得当前对象中的标签集合:Set labels()
(4)从当前对象中移除某个标签所关联的时间段:boolean remove(L label)
(5)返回某个标签对应的时间段的开始时间:long start (L label)
(6)返回某个标签对应的时间段的结束时间:long end (L label)

3.2.2 局部共性特征的设计方案
设计CommenIntervalSet类,来实现IntervalSet接口:
1.属性:设置startMap,endMap两个属性

2.AF,RI
AF:通过map分别记录标签、开始时间;标签,结束时间,以此表示整个时间线。
RI:输入的时间应大于等于0,新插入的标签和已经存在的标签不应冲突,新插入的时间段和已安排的时间段不应重合。

3.检查表示泄露
checkRep()检查开始时间结束时间是否小于0.

4.方法
一共写了八种方法,其中定义的新方法有getstartMap(),getendMap(),反别返回两张图。剩下的六种方法为对IntervalSet的重载:
(1)在当前对象中插入新的时间段和标签:void insert(long start, long end, L label)。参数分别为事件的开始时间,结束时间,标签。如果新插入的标签已经存在,或欲插入的时间段已经被占用,则抛出异常。
这里对于标签的检测是容易的,对于时间段重叠的检测策略是:新时间开始早于某时间段的结束且新时间段的结束小于某时间段的开始,必重复。

插入新的时间段后,需checkRep()。
(2)获得当前对象中的标签集合:Set labels()
出现在startMap中的标签一定和出现在 endMap中标签相同,因此只需遍历一个图,将所有标签放入一个新的集合,返回该集合。
(3)从当前对象中移除某个标签所关联的时间段:boolean remove(L label)
主要需要将两张图中存储的关于该标签的信息全部删除。删除采用迭代器Iterator遍历。
for (Iterator iterator = endMap.keySet().iterator(); iterator.hasNext()😉 {
L key = iterator.next();
if (key.equals(label)) {
iterator.remove();

			}
		}

(4)返回某个标签对应的时间段的开始时间:long start (L label)
直接利用Map本身的方法,通过键值标签,返回value值。在这里需检测输入参数标签是否在map中,如果不存在,向上抛出异常。
(5)返回某个标签对应的时间段的结束时间:long end (L label)
与long start (L label)相似。
(6)String toString()
即将设计的CommonIntervalSet可视化,直接遍历一张图,然后从另一张图获取结束时间信息,练成字符串即可。

5.Junit测试

3.2.3 面向各应用的IntervalSet子类型设计(个性化特征的设计方案)
DutyIntervalSet继承CommonIntervalSet类。个性化的特征是需要返回设定的一段时间段内的空余时间。
空闲时间段的计算策略:如果时间段内没有未安排的时间,那么安排的各个时间段一定首尾相接。我的方法是将startMap, endMap中表示开始时间和结束时间分别存储在两个集合,然后做对称差。这里对于最初开始时间和最初结束时间的处理是:将整个待安排时间段的开始时间加入结束时间的集合,这样如果开始时间的集合中有等于待安排时间的,可以对称差约掉;将待安排时间段的结束时间加入开始时间的集合。具体操作如下:

求集合对称差:
在这里插入图片描述
在这里插入图片描述

然后对对称差集内部排序,从第一个数起两两一组之间的时间即为空余段。
3.3 面向可复用性和可维护性的设计:MultiIntervalSet
3.3.1 MultiIntervalSet的共性操作
(1)创建一个空对象:empty()或不带任何参数的构造函数
(2)创建一个非空对象:构造函数 MultiIntervalSet(IntervalSet initial),利用 initial 中包含的数据创建非空对象
(3)在当前对象中插入新的时间段和标签:void insert(long start, long end, L label)
(4)获得当前对象中的标签集合:Set labels()
(5) 从当前对象中移除某个标签所关联的所有时间段:boolean remove(L label)
(6) 从当前对象中获取与某个标签所关联的所有时间段
3.3.2 局部共性特征的设计方案
将MultiIntervalSet实现为具体类。
1.属性
private List<IntervalSet> multi = new ArrayList<>()
2.AF:采用List<IntervalSet>存储时间安排,如果标签重复,存储在下一条IntervalSet上。
RI:保持CommomIntervalSet的RI.
3.构造器
如果没有初始的IntervalSet,默认构造器;如果有初始IntervalSet,将它加入构造的multi。
4.方法
(1)checkoverlap(long start, long end)
检测该时间段是否和multi中已有的时间段发生重合,如果重合,返回1,不重合返回0。
检测策略:设置标记flag=0,遍历multi中每条IntervalSet的时间段安排,如果和某条时间段重合,flag++,最后根据flag值返回。

(2)insert(long start, long end, L label)
首先检测时间段是否和已有时间段冲突,如果冲突,直接抛出异常。

在时间段不冲突的前提下,遍历multi的每条IntervalSet,如果标记不冲突,就加入该条IntervalSet,如果冲突,看下一条。如果最终还是没有加入,就为该记录新建一个IntervalSet,然后加入multi。

(3)removeAll(L label)
移除multi中关于label的所有记录。
遍历multi中每条IntervalSet,然后复用了IntervalSet中的remove方法进行删除。
(4)Set labels()
获取所有的标签。这里直接遍历后将标签加入新建的Set,不再赘述。
(5)IntervalSet intervals(L label)
将一个标签的所有时间段记录整合成一个IntervalSet,标签为时间段记录的序号。如果在multi中不存在标签L label则向上抛出异常。
新建一个IntervalSet对象,遍历multi,如果有标签为label的时间段记录,使用IntervalSet接口中insert方法,加入新建的对象。

(6)String toString()
将multi 可视化。首先获取multi中所有的标签,然后按获取的标签顺序在Multi中搜索某一标签对应的时间段信息,加入要返回的字符串,最后返回。
5.Junit测试

3.3.3 面向各应用的MultiIntervalSet子类型设计(个性化特征的设计方案)

  1. ProcessIntervalSet继承MultiIntervalSet
    新定义了方法long execute(Process n, long maxexecutetime, long starttime):为进程随机安排执行时间,如果满足目标进程的插入需求,则将目标需求放入进程执行时间线中。

随机生成一个不大于maxexecutetime的时长,然后根据目标进程的信息判断,如果在该时间段内执行次进程会不会超过此进程的最长执行时间,如果会超出,则该时间段内不执行任何进程;如果不会超出,则执行该进程并且该进程属性中的已执行时长更新。

  1. CourseIntervalSet继承MultiIntervalSet
    这里继承后没有继续拓展功能。
    3.4 面向复用的设计:L
    1.Employee
    (1)三个属性,分别为员工姓名、职位、电话,都为String类型,并且为private
    (2)构造器:

(3)三个方法getname(),getjob(),getphone()分别获取员工的名字、职位、电话。

2.Process
(1)一共设置七个属性:进程名、PID、执行的最短时间、执行的最长时间、是否执行完、已经执行的时间、距离最长执行时间的时间差。

(2)构造:初始化的时候完成设置成false,已经执行时长为0
(3)方法:七个方法,分别用来获取七个属性。

3.Course
(1)属性:6个属性,课程ID、课程名、授课教室、上课地点、每周课时数、已经排入课表的每周的课时数。

(2)构造方法:在构造时将已经排入课表的每周课时数初始化为0。
(3)方法:六个方法分别用于获取六个属性。
3.5 可复用API设计
3.5.1 计算相似度
按照时间轴从早到晚的次序,针对同一个时间段内两个对象里的 interval,若它们标注的 label 等价,则二者相似度为 1,否则为 0;若同一时间段内只有一个对象有 interval 或二者都没有,则相似度为 0。将各interval 的相似度与 interval 的长度相乘后求和,除以总长度,即得到二者的整体相似度。
3.5.2 计算时间冲突比例
我在应用3中计算了时间冲突的比例。我设置了全局变量overlaptime。因为一周可以排课的课时数为527=70,每次排课都得排两课时,因此每周排课的机会为35次。我调用CourseIntervalSet类里的checkoverlop方法,如果排课时发生一次时间冲突,就给overlap加一。最后冲突比例为(double)overlap/35.

3.5.3 计算空闲时间比例
在应用3中计算了空闲时间的比例。我创建了Set,记录课表一周内课程的开始时间,当一个课程的开始时间不包含于Set时,将这个新的开始时间加入集合。只需计算(35-Set中的元素个数)/35,即可得到空闲比例时间。

3.6 应用设计与开发
利用上述设计和实现的ADT,实现手册里要求的各项功能。
3.6.1 排班管理系统
1.属性
一个属性:公司员工表
private static List allemployee = new ArrayList<>();
创建DutyInterval类的dutylist对象,存储值班表。

2.方法
(1)insertemployee(Employee n)
向公司员工表添加员工。如果该员工已经存在,返回false,否则添加,返回true
(2)Long getdate(Long year, Long month, Long day)
将输入的日期年月日转化为Long。
Long date = year * 10000 + month * 100 + day;
(3)insert(Long startdate, Long enddate)
插入用户想要添加的排班记录,需要用户键入:想要增加的记录条数,值班人,开始值班时间,结束值班时间。如果用户输入的值班人不再公司员工表里,向上抛出异常。如果用户输入的值班人合法,则调用DutyInterval的insert方法,加入该记录。最后调用DutyInterval的Nooccupy方法,计算目前还未被排班的时间段。
(4)deleteemployee(Long startdate, Long enddate)
当公司需要删除某员工时调用该方法。删除某员工前,应先在值班表中将他删除,再从公司人员名单里删除。值班表删除时,用DutyInterval的remove方法,人员名单删除时,用迭代器。
(5)自动排班autoduty(Long startdate, Long enddate)
输入开始和结束日期后,根据公司人员名单进行排版。基本实行平均分配的原则,但当总天数无法整除员工人数,最后一个人需要值班到截至日期。
(6)showduty()
将值班表可视化。

(7)main函数
执行App的主要流程:
我预先在人员名单内直接加入了三个人:

首先让用户输入开始日期和截至日期,并检查输入的合法性,如果不合逻辑,需要用户重新输入,保证程序的健壮性。

如图当输入年份小于2021时需要重新输入,输入月份和天数不对应时,也要重新输入。
然后顺序执行:用户是否需要添加记录,如果是,进入添加记录的流程;用户是否需要删除员工,如果是,进入删除流程;用户是否需要自动排班,如果是,自动排班。
最后输出排班表。

3.6.2 操作系统的进程调度管理系统
1.属性
待执行进程表
private static List processlist = new ArrayList<>();
创建ProcessIntervalSet类的对象记录进程执行情况
2.方法
(1)addprocesslist(Process n)
向进程列表中添加进程
(2)maxexecutetime(),根据进程的属性,即最大执行时间,返回每次可以随机产生的时间长度的最大值。
(3)Random()
随机选择未执行完的进程。每次执行一个进程后,需检查它的已执行时间是否大于最小执行时间,若大于,则将它从进程标中删除。

进程标中随机选择进程用了Random类:

(4)Shortprior()
每次选择进程的时候,优先选择距离其最大执行时间差距最小的进程。实现的时候我对进程列表根据进程的resttime属性排序,每次取第一个。执行完进程后检查该进程是否被执行完,如果执行完,从进程列表中删除该进程。
最后需要更新排序。

(5)tostring()
将进程执行状态可视化。

(6)main函数
预先在进程表中放置一些进程。

然后进入流程:用户是否需要增加进程,如果需要,进入增肌进程流程;

让用户选择进程执行方式:随机或最短进程优先。
选随机,进入随机执行流程;选优先,进入优先执行流程。最后展示进程执行状态。
随机执行结果:

最小优先:

3.6.3 课表管理系统
1.创建对象
把一周的时间看成一个MultiIntervalSet,整个课表就是List类的对象

2.方法
(1)手动排课
用户输入需排课程的起止时间,如果时间未冲突,使用 CourseIntervalSet的方法排课,如果时间冲突,新建CourseIntervalSet对象,加入课程后再将该对象加入timetable。

(2)计算空闲率freepersent()
已经再API章节提到,不再赘述。
(3)showtimetable(Calendar c1)
查看某天课表。用户输入年月日后,我会将他转化成周中日。然后遍历记录排课基本信息的coursestartmap,当它的value值与需要查看的周中日对应时,输出该课程信息。
下图为利用calendar类,计算周中日

(4)main 函数
首先进入流程:用户是否需要添加新的课程,如果是,就在课程列表加入新课程。

然后需要用户输入学期的开始日期和持续周数,App可自动计算结束日期并输出。
用户是否需要手动添加课表,如果是,进入排课表流程,添加完后,计算空闲率,重复率。
用户是否需要查询某天课表,若需要,进入查看某天课表流程。

3.8 应对面临的新变化
3.8.1 变化1
我在CommonIntervalSet里添加了新的方法insertchange,该方法和insert方法几乎相同,只是不做对标签重复的检查。这样就可以插入多端记录了。变化代价较小。

3.8.2 变化2
原来如果时间重复,新建一个multiIntervalSet类的对象,把课程插入新对象后,再把新对象放入课程表。现在改成如果时间重复,也不再新建,而是直接输出时间重复即可。变化代价很小。

3.9 Git仓库结构
请在完成全部实验要求之后,利用Git log指令或Git图形化客户端或GitHub上项目仓库的Insight页面,给出你的仓库到目前为止的Object Graph,尤其是区分清楚change分支和master分支所指向的位置。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值