软件构造Lab3记录

First Post:

Last Update:

Word Count:
2.6k

Read Time:
9 min

软件构造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 trackList) { 根据传入的trackList构造concreteCircularOrbit

之后再根据具体应用实现子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分支所指向的位置。

实验总结

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

代码可复用性较低,设计模式记忆不熟

针对以下方面的感受

  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”的难度主要体现在哪些地方?你是如何克服的?
    
  7. 你在完成本实验时,是否有参考Lab4和Lab5的实验手册?若有,你如何在本次实验中同时去考虑后续两个实验的要求的?
    
  8. 关于本实验的工作量、难度、deadline。
  9. 到目前为止你对《软件构造》课程的评价。
    

回答:
1. 复用减小了工作量,但增加了思考量。
2. 时刻提醒自己注意自己的设计,注意防止泄露
3. 使用别人的API画图很方便。
4. 合理运用设计模式十分有许多好处,针对不同的ADT使用恰当的设计模式很重要
5. 避免了自己输入的繁琐过程。
6. 对物体的抽象
7. 无手册
8. 难度中等 工作量很大 ddl跟期末考试重合导致时间更紧张了
9. 工作量很大。收获颇丰。