软件构造lab3

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

Lab 3实验报告
 

姓名

王尧

学号

1190201812

班号

1903012

目录

 

1 实验目标概述

本次实验覆盖课程第 2、3 章的内容,目标是编写具有可复用性和可维护性的软件,主要使用以下软件构造技术:

子类型、泛型、多态、重写、重载

继承、代理、组合

语法驱动的编程、正则表达式

API 设计、API 复用

本次实验给定了三个具体应用(值班表管理、操作系统进程调度管理、大学课表管理),学生不是直接针对每个应用分别编程实现,而是通过 ADT 和泛型等抽象技术,开发一套可复用的 ADT 及其实现,充分考虑这些应用之间的相似性和差异性,使 ADT 有更大程度的复用(可复用性)和更容易面向各种变化(可维护性)。

2 实验环境配置

简要陈述你配置本次实验所需环境的过程,必要时可以给出屏幕截图。

特别是要记录配置过程中遇到的问题和困难,以及如何解决的。

在这里给出你的GitHub Lab3仓库的URL地址(Lab3-学号)。

3 实验过程

请仔细对照实验手册,针对每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。

3.1 待开发的三个应用场景

值班表管理:一个单位由n位员工,在一些时间段中安排值班,每个时间段只有一名员工且在一个时间段必须要有员工,值班表需要记录员工的名字,职位,电话号码,以便于联系

操作系统进程进程调度:进程被调度后在cpu中执行,操作系统决定在不同时间段执行那个进程,并且可以挂起某个正在执行的进程,并且在后续中可以回复被挂起的进程。每个时间段只有一个进程可以执行,其余进程应处于休眠状态,进程的执行可以分为多个时间段,在特定时刻,cpu可进行随机调度

大学课表管理:课程需要特定的教室和特定的教师。假设各周的课表都是完全一样的,同样的课程安排将以“周”为单位进行周期性的重复,直到学期结束;一门课程每周可以出现 1 次,也可以安排多次,且由同一位教师承担并在同样的教室进行;允许课表中有空白时间段;同一个时间段内可以安排不同的课程;一位教师也可以承担课表中的多门课程

相同之处:都包含具有不同特征的时间段集合的对象,每个时间段对应不同的对象

不同之处:有三个维度的差异。①是否允许时间轴上有空白。在应用1中,不允许有空白;在应用2和应用3中,允许有空白。②是否允许不同的 interval 之间有重叠。在应用1和应用2中,不允许有重叠;在应用3中,允许有重叠。③是否包含周期性的时间段。应用 3 中以“一周”为单位重复某个课程,但应用1和应用2中不存在这种情况。

3.2 面向可复用性和可维护性的设计:IntervalSet<L>

该节是本实验的核心部分。

3.2.1 IntervalSet<L>的共性操作

我们采用的是方案二

创建对象

插入时间段

移除时间段

3.2.2 局部共性特征的设计方案

开头的书写

插入操作

判断插入时间段与已有时间段是否产生冲突

删除操作

此外,为判断相同标签下插入相连的时间段,这些时间段是否要进行合并,哦我们设计了一个合并开关方法

这个方法将key置为1,来进行操作

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

对第一个应用场景的处理

首先初始化及各部分含义:

Employee类型的list,用于储存排班表中的员工数据。

IntervalSet<Employee> 类型的时间线表示对象,由IntervalSet中的方法产生。

Bounds是Rosterlist中表示信息的数据结构,建立引用。

Rosterrule用于储存排班表的具体信息。

重写tostring和equals方法

设置排班表要求(截图在下方)

1.      开始时间小于结束时间

2.      添加员工

3.      移除员工

4.      根据姓名查找员工信息

5.      将一个员工加入到值班表中

6.      检查值班表是否排满

7.      生成值班表

8.      显示值班表

9.      显示空闲时间占总时间段的比例

3.3 面向可复用性和可维护性的设计:MultiIntervalSet<L>

3.3.1 MultiIntervalSet<L>的共性操作

共性操作与上面大致相同

除了创建时间段,插入时间段,移除时间段还包含intervalset

3.3.2 局部共性特征的设计方案

如下图所示

 

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

对剩余两个的处理:

Process的:

数据结构的定义

Processlist存储要调度的进程信息。

Schedule为MultiIntervalSet类型,提供相应的数据结构和方法。

Bounds储存实际的时间段信息。

Timeline 为当前进程执行到的时间。

具体操作:

1.      加入新进程

2.      得到进程运行时间

3.      进程调度函数

4.      检查进程是否都已经结束

5.      显示当前进程和进程调度情况

Course:

数据结构的定义:

Courselist存储课程的相关信息

Weeks为时间段的一个list,第n个元素代表n+1周的课程的时间段信息。

Bounds用于对每一周的课程安排信息的list的引用。

此外,还有

Week为本学期的总周数。

startTime储存学期开始日期

实现类:

基本功能:

1.      初始化学期时间段

2.      设置学期周数和开始时间

3.      添加新课程

4.      检查所添加课程与已有课程是否冲突

5.      检查某一课程学时是否排够

6.      检查所有课程学时数是否已满

7.      安排课程

8.      显示没有排满的课程

9.      显示某周剩余空闲时间比例

10.   显示每一周空闲时间所占比例

11.   计算某一周的课程重复率

12.   计算每一周的重复

13.   通过课程名显示课程信息

14.   显示某一天的时间表

3.4 面向复用的设计:L

设计三个应用的不同标签,分别是员工(Employee),进程(Process),课程(Course)

利用这三个分别完成对CourseIntervalSet,,DutyIntervalSet,ProcessSchedule的书写

3.5 可复用API设计

3.5.1 计算相似度

3.5.2 计算时间冲突比例

3.5.3 计算空闲时间比例

某一周的空闲时间

每一周的空闲时间比例

空闲时间段占总时间段的比例

3.6 应用设计与开发

利用上述设计和实现的ADT,实现手册里要求的各项功能。

3.6.1 排班管理系统

排班管理系统我们进行了不同的读入,手动读入和自动读入

选择读入方式(手动/文件)

手动读入

文件读入

3.6.2 操作系统的进程调度管理系统

输入提示:

3.6.3 课表管理系统

3.7 基于语法的数据读入

修改“排班管理”应用以扩展该功能。

定义正则表达式用来匹配文件中数据

再下来,对文件中读入的数据进行分割

并针对不同类型数据进行挑选,对数据进行初始化

3.8 应对面临的新变化

3.8.1 变化1

在最初设计时已考虑此变化,因此代价不大

3.8.2 变化2

在最初设计时已考虑此变化,因此代价不大

3.9 Git仓库结构

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

4 实验进度记录

请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。

每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。

不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。

日期

时间段

计划任务

实际完成情况

          6.29-6.30

早八点到晚上十点

Intervalset接口和multiIntervalset接口

基本完成

7.1

早上十点到晚上23时

三个子类的实现

基本完成三分之一

7.2-7.3

全天

三个字类的实现

基本完成

5 实验过程中遇到的困难与解决途径

遇到的难点

解决途径

编写过程中遇到了很多健壮性问题

对每一个步骤可能的输入进行分析进行分析,对非法情况做出提示。

不知道正则表达式如何完成对文件信息的抽取

先查阅资料,然后对正则表达式进行小的书写,然后再进行大的书写

装饰器的用法上面不是很懂,你知道如何才能实现我们所需要的功能

在网络上查找相应的资料并进行归纳整理,逐步完成装饰器的使用

6 实验过程中收获的经验、教训、感想

6.1 实验过程中收获的经验和教训

设计adt的过程中一定要先考虑,不然写到后面就尾大不掉,只能重新设计,此外,再编写代码时我们遇到的健壮性问题一定要先考虑再写,不然最后的程序会显得比较乱,并且风险也会更高一些。

6.2 针对以下方面的感受

(1)   重新思考Lab2中的问题:面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?本实验设计的ADT在三个不同的应用场景下使用,你是否体会到复用的好处?

面向adt的编程需要我们从实际出发进行抽象,并进行设计,有较好的扩展性和复用性。直接面想应用场景编程只针对具体的应用,每次更换场景时,都要重新编程,这样使得扩展性较差,难以进行复杂的应用场景编程。

(2)   重新思考Lab2中的问题:为ADT撰写复杂的specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后的编程中坚持这么做?

这些工作使得客户端了解各方法的功能但无法得知内部具体实现,可以防止内部变量被客户端恶意修改,时刻检查表示不变量,保证安全性,同时,好的注释对于代码部分来说可以减轻阅读代码的工作。我愿意坚持这么做。

(3)   之前你将别人提供的API用于自己的程序开发中,本次实验你尝试着开发给别人使用的API,是否能够体会到其中的难处和乐趣?

因为api面向的场景是广泛的,因此我们开发编译的难度较大,但是,也正因难度较大,我们在编译过程中能体会到不少的乐趣,同时,完成后会有较大的成就感

(4)   你之前在使用其他软件时,应该体会过输入各种命令向系统发出指令。本次实验你开发了一个解析器,使用语法和正则表达式去解析输入文件并据此构造对象。你对语法驱动编程有何感受?

语法驱动编程可以提供很大的便利,方便用户与开发者,并且有很好的可维护性

(5)   Lab1和Lab2的大部分工作都不是从0开始,而是基于他人给出的设计方案和初始代码。本次实验是你完全从0开始进行ADT的设计并用OOP实现,经过五周之后,你感觉“设计ADT”的难度主要体现在哪些地方?你是如何克服的?

难度主要来源于设计:对抽象的把握上面。我们把我们涉及到的具体场景进行分析,确立好基本框架,在一步步填充即可

(6)   “抽象”是计算机科学的核心概念之一,也是ADT和OOP的精髓所在。本实验的五个应用既不能完全抽象为同一个ADT,也不是完全个性化,如何利用“接口、抽象类、类”三层体系以及接口的组合、类的继承、设计模式等技术完成最大程度的抽象和复用,你有什么经验教训?

接口、抽象类、类的抽象程度一定是逐渐降低的,将所有应用的共性抽象为接口,然后在抽象类以及类中添加新的特性。通过接口的组合可以形成新的接口,并可以具备不同接口中的抽象。类的继承也可以增加更具体的新的特性。同时,使用正确的设计模式可以使得代码的可复用性和可维护性最大化。

(7)   关于本实验的工作量、难度、deadline。

本实验难度较大,但可接受。工作量很大,尤其是时间在考试周,时间有点紧张,希望老师以后能安排的更合理一些

(8)   到目前为止你对《软件构造》课程的评价。

这门课总体来说是蛮好的,就是在一定程度上课时安排的不是很好,尤其是与csapp一起,压力太大了,但是对于我们对编程的把握来说,是有很大好处的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值