软件构造Lab3记录
Last Update:
Word Count:
Read Time:
软件构造Lab3记录
实验目标概述
目标是编写具有可复用性和可维护性的软件,主要使用以下软件构造技术:
- 子类型、泛型、多态、重写、重载
- 继承、委派、CRP
- 语法驱动的编程、正则表达式
- 设计模式
本次实验给定了多个具体应用,学生不是直接针对每个应用分别编程实现,而是通过 ADT 和泛型等抽象技术,开发一套可复用的 ADT 及其实现,充分考虑这些应用之间的相似性和差异性,使 ADT 有更大程度的复用(可复用性)和更容易面向各种变化(可维护性)。
实验过程
待开发的三个应用场景
首先请列出你要完成的具体应用场景(至少3个,1和2中选一,3必选,4和5中选一,鼓励完成更多的应用场景)。
TrackGame
AtomStructure
分析你所选定的多个应用场景的异同,理解需求:它们在哪些方面有共性、哪些方面有差异。SocialNetworkCircle
首先,他们都是多轨道结构,它们的轨道十分类似,都可以看成一个只有名字和半径属性的圆。它们的轨道物体也有一些相似之处:比如都要求有名字。他们都要求有对于轨道、轨道上的物体的一系列增删改查的操作的要求。
不同之处:
有的要求各个物体之间有有向或无向关系,有的各个物体之间没有区别比如电子,有的有区别比如运动员。 。
面向复用的设计:CircularOrbit<L,E>
- setCentralObject(L centralObject); 设置中心物体
- getCentralObject(); 返回中心物体
- addTrack(Track t); 增加一条轨道
- removeTrack(Track t); 删除一条轨道
- getTrackNum(); 返回轨道数目
- getObjectNumonTrack(Track t); 统计一条轨道有多少物体
- addObjectToTrack(Track t, E object); 向轨道上增加物体
- removeObjectOnTrack(Track t, E object); 删去一个轨道上的某个物体
- addtrackRelation(E object1, E object2, double distance) 在两个轨道物体之间新增关系
- addcentralRelation(E object, double distance); 在轨道物体和中心物体之间新增关系
- getObjectDistributionEntropy(); 计算轨道系统的信息熵
- getLogicalDistance(E e1, E e2); 获得两物体间逻辑距离
- getDifference(CircularOrbit<L, E> c); 比较当前orbit和目标orbit的不同
- return 一个different对象,记录两个orbit的区别
- getSortedTracks(); 获得当前orbit包含的所有轨道按半径排列成的链表
- drawpicture(); 可视化方法
- contains(E e); 判断当前Orbit是否包含某个元素e
- getObjectTrack(E e); 返回某个元素e所在的Object对象
- getCentralConnectedObject(); 返回与中心连接的物体构成的集合
- getTrackConnectedObject(E object) 返回与某个轨道物体连接的所有物体
- checkRep(){ 检查合法性
面向复用的设计:Track
有两个域 name名字 和radius半径,实现Comparable依靠半径排序。
面向复用的设计:L
只有一个域名字,方法:
Name的getter方法和CentralObject(String name) 构造方法
以及checkRep() 方法检查名字非空。
面向复用的设计:PhysicalObject
只有一个域名字,方法:
Name的getter方法和PhysicalObject (String name) 构造方法
以及checkRep() 方法检查名字非空。
设计模式应用
3.9.1 工厂设计模式:
在每个具体Object类中实现一个静态的getInstance方法,不需要实例化Athlete即可调用
Builder设计模式:
设计抽象CircularOrbitBuilder类作为具体builder类的父类,包含一个concreteCircularOrbit就是正在build过程中的Orbit
- getConcreteCircularOrbit() { 返回构造完成的对象
- abstract void createCircularOrbit(); 抽象方法,实现时创建具体类型的Orbit
- bulidPhysicalObjects(L centralObj, Map<Track, List
> ObjectMap) 根据传入的centralObj和ObjectMap初始化concreteCircularOrbit中的关系Map - bulidTracks(List
之后再根据具体应用实现子builder类。
Iterator设计模式
设计OrbitIterator类实现Iterator接口。
ObjectList是保存所有物体的list,每次取next从ObjectList取值。
Index是迭代指针。
- OrbitIterator(Map<Track, List
> orbitMap) 构造函数,根据关系Map orbitMap构造一个ObjectList作为迭代的输出 - hasNext() 判断迭代指针是否等于size,如果是则没有下一个了
- next() 取元素,Index++
strategy设计模式
在TrackGame中设计一个strategy接口和两个具体实现的strategy类,分别能执行随机排序和按成绩排序。
应用设计与开发
利用上述设计和实现的ADT,实现手册里要求的各项功能。
以下各小节,只需保留和完成你所选定的应用即可。
TrackGame
Athlete类继承自PhysicalObject作为轨道物体,具有以下新增属性
TrackCircularOrbit类继承自ConcreteCircularOrbit作为具体轨道结构
重写了toString方法输出多轨道结构
重写了checkRep()方法按要求检查轨道特性
TrackCircularOrbitBuilder类继承自CircularOrbitBuilder
主要是重写了createCircularOrbit方法,生成TrackCircularOrbit。
GameType轨道类型,trackNum轨道数量,athleteList运动员列表
trackOrbitList是一个TrackCircularOrbit的list结构,因为每次安排比赛生成多个轨道结构,用这个list存放生成的所有TrackCircularOrbit。
trackBuilder是TrackCircularOrbitBuilder的一个实例。用来build每一个TrackCircularOrbit对象。
- GameMenu() { 菜单
- gameMain 功能主体,读取文件,构造每个TrackCircularOrbit,实现菜单中的每个功能。
- arrangeOrbit(Strategy strategy) 策略安排方法,根据athleteList和trackNum和构造策略,生成构造方案
AtomStructure
Particle类继承自PhysicalObject作为轨道物体,具有以下新方法:
getElectron返回一个没有区别的电子,
getNucleus返回一个有名字区别的原子核
AtomCircularOrbit类继承自ConcreteCircularOrbit作为具体轨道结构
主要是重写了toString方法。新增方法如下:
方法 功能
transit(Track t1, Track t2) { 电子跃迁方法
removeElectron(Track t) 从某条轨道删去一个电子,因为电子互相之间没有区别,所以只需一个轨道参数。
重写toString 输出轨道结构
AtomCircularOrbitBuilder类继承自CircularOrbitBuilder
主要是重写了createCircularOrbit方法,生成AtomCircularOrbit。
AtomGame类:具有下列域:
trackNum轨道数量,Nucleus原子核
transitCareTaker是TransitCareTaker的一个实例。用来实现备忘录模式,具体是把每次跃迁记录成Memento保存下来,恢复时弹出上一个Memento。
atomCircularOrbit就是当前使用的轨道系统实例。
SocialNetworkCircle
Person类继承自PhysicalObject作为轨道物体
Age保存年龄,gender是性别
relationKeeper类和是一个用来保存文件读入的类,因为读取文件读入的过程没法将读取到的人名 马上与实例对应起来,所以构造relationKeeper保存每个关系的人名string。
SocialNetCircularOrbit类继承自ConcreteCircularOrbit作为具体轨道结构
- reArrange 重整关系网络
- 重写drawpicture方法 实现可视化,这个轨道结构要求可视化关系,所以加上画边的功能。
- 重写toString 输出轨道结构
SocialNetCircularOrbitBuilder类继承自CircularOrbitBuilder
主要是重写了createCircularOrbit方法,生成SocialNetCircularOrbit。
新增bulidRelations,从读取的文件输入构造人际关系图,随后通过reArrange构造轨道关系图。
personList人列表,centralUser中心物体 ,keeperList是一个关系读取寄存器
socialCircularOrbit是当前操作的SocialNetCircularOrbit对象。
socialCircularOrbitBuilder是SocialNetCircularOrbitBuilder的一个实例。用来build每一个SocialNetCircularOrbit对象。
计算信息扩散度:
思路:主要利用队列+BFS算法,对于起始点:
设置map为<起始点,中心点到起始点的权重>,随后对BFS算法找到的每个点,
设置map为<上一个点,上一个点的权x上一个点到这个一个点的关系的权>。
例如图中存在关系a->b->c, a为中心点,则亲密度为:value(a,b)+ value(a,b) x value(b,c)
Git仓库结构
请在完成全部实验要求之后,利用Git log指令或Git图形化客户端或GitHub上项目仓库的Insight页面,给出你的仓库到目前为止的Object Graph,尤其是区分清楚312change分支和master分支所指向的位置。
实验总结
实验过程中收获的经验和教训
代码可复用性较低,设计模式记忆不熟
针对以下方面的感受
- 重新思考Lab2中的问题:面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?本实验设计的ADT在五个不同的应用场景下使用,你是否体会到复用的好处?
- 重新思考Lab2中的问题:为ADT撰写复杂的specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后的编程中坚持这么做?
- 之前你将别人提供的API用于自己的程序开发中,本次实验你尝试着开发给别人使用的API,是否能够体会到其中的难处和乐趣?
在编程中使用设计模式,增加了很多类,但在复用和可维护性方面带来了收益。你如何看待设计模式?
- 你之前在使用其他软件时,应该体会过输入各种命令向系统发出指令。本次实验你开发了一个解析器,使用语法和正则表达式去解析输入文件并据此构造对象。你对语法驱动编程有何感受?
Lab1和Lab2的大部分工作都不是从0开始,而是基于他人给出的设计方案和初始代码。本次实验是你完全从0开始进行ADT的设计并用OOP实现,经过三周之后,你感觉“设计ADT”的难度主要体现在哪些地方?你是如何克服的?
你在完成本实验时,是否有参考Lab4和Lab5的实验手册?若有,你如何在本次实验中同时去考虑后续两个实验的要求的?
- 关于本实验的工作量、难度、deadline。
到目前为止你对《软件构造》课程的评价。
回答:
1. 复用减小了工作量,但增加了思考量。
2. 时刻提醒自己注意自己的设计,注意防止泄露
3. 使用别人的API画图很方便。
4. 合理运用设计模式十分有许多好处,针对不同的ADT使用恰当的设计模式很重要
5. 避免了自己输入的繁琐过程。
6. 对物体的抽象
7. 无手册
8. 难度中等 工作量很大 ddl跟期末考试重合导致时间更紧张了
9. 工作量很大。收获颇丰。