SC_lab3 复用。。。
Lab 3实验报告
1 实验目标概述
本次实验覆盖课程第 3、5、6 章的内容,目标是编写具有可复用性和可维护 性的软件,主要使用以下软件构造技术:
子类型、泛型、多态、重写、重载
继承、代理、组合 常见的 OO 设计模式
语法驱动的编程、正则表达式 基于状态的编程
API 设计、API 复用 本次实验给定了五个具体应用(径赛方案编排、太阳系行星模拟、原子结构
可视化、个人移动 App 生态系统、个人社交系统),学生不是直接针对五个应用
分别编程实现,而是通过 ADT 和泛型等抽象技术,开发一套可复用的 ADT 及其 实现,充分考虑这些应用之间的相似性和差异性,使 ADT 有更大程度的复用(可 复用性)和更容易面向各种变化(可维护性)
2 实验环境配置
通过实验手册所给的url建立github的实验三的仓库,然后通过git将本地仓库与github上的远程仓库连接,配置完成;
3 实验过程
请仔细对照实验手册,针对每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1 待开发的三个应用场景
首先请列出你要完成的具体应用场景(至少3个,1和2中选一,3必选,4和5中选一,鼓励完成更多的应用场景)。
TrackGame
AtomStructure
SocialNetworkCircle
分析你所选定的多个应用场景的异同,理解需求:它们在哪些方面有共性、哪些方面有差异。
共性:全部是多轨道系统,其中trackgame没有中心物体,但可以把比赛种类抽象为一个中心物体。这样就可以把三个应用全部视为有中心物体的轨道系统。
则可以设计统一的接口和抽象类。根据应用的开发要求,三者的增删轨道,增删轨道物体,也具有相同性,所以这部分的gui具有共性。
差异:轨道物体和中心物体的具体属性不太相同,但不是太大的问题。针对每个应用,又多出一些特殊的操作,所以对接口的实现类,要在分为三个具体的实现类。同时,在可视化和设计gui时,三个应用也有很大的不同,这部分也要分开写。此外,api部分,只又部分的应用会用到api的功能。所以也需要特殊对待。
3.2 基于语法的图数据输入
-
TrackGame部分的正则表达式输入
String athletepattern = “^Athlete\s*::=\s*<\s*[A-Za-z]+\s*,\s*[0-9]{1,3}\s*,\s*[A-Z]{3}\s*,\s*[0-9]{1,2}\s*,\s*[0-9]{1,2}\.\d{2}\s*>”;
String gamepattern = “^Game\s*::=\s*[0-9]{3}”;
String numpattern="^NumOfTracks\s*::=\s*[0-9]{1,2}"; -
AtomStructure部分的正则表达式输入
String elementpattern = “^ElementName\s*::=\s*[A-Z]{1}[a-z]?”;
String numpattern="^NumberOfTracks\s*::=\s*[0-9]{1,2}";
String electronpattern="^NumberOfElectron\s*::=\s*(\s*[0-9]/[0-9]+\s*;)+\s*[0-9]/[0-9]+";
3. SocialNetworkCircle部分的正则表达式输入
String centraluserpattern = “^CentralUser\s*::=\s*<\s*[a-zA-Z0-9]+\s*,\s*[0-9]{1,3}\s*,\s*(F|M)\s*>”;
String friendpattern="^Friend\s*::=\s*<\s*[a-zA-Z0-9]+\s*,\s*[0-9]{1,3}\s*,\s*(F|M)\s*>";
String tiepattern="^SocialTie\s*::=\s*<\s*[a-zA-Z0-9]+\s*,\s*[a-zA-Z0-9]+\s*,\s*(1|0).?[0-9]{0,3}\s*>";
3.3 面向复用的设计:CircularOrbit<L,E>
3.3.1 接口CircularOrbit<L,E>
为三个轨道系统设计的统一的接口,具体方法如下
- public boolean addTheCenter(L theCenter);
添加轨道系统的中心物体 - public boolean addTheTrack(Track theTrack);
为轨道系统添加轨道 - public boolean addThePoint(E point);
添加轨道物体 - public boolean setRelation(E obj1, E obj2,double tie);
设置添加两个轨道物体之间的关系 - public boolean setCenterRelation(L theCenter, E point,double tie);
设置添加中心物体额轨道物体的关系 - public boolean setTrackandPhy(Track track,E point);
将轨道物体加入到轨指定轨道上去,形成(轨道,该轨道上所有轨道物体的集合)这种形式的集合。 - public double getObjectDistributionEntropy();
计算该系统的熵值,将api中的方法移动到这里,更加方便计算。 - public Set<Relation<E, E>> getErela();
get方法,返回所有轨道物体之间关系的集合。 - public Set<Relation<L, E>> getCrela();
get方法,返回所有中心物体与轨道物体的关系的集合。 - public Set getPhy();
get方法,返回所有轨道物体的集合。 - public Map<Track, Set> getTrack();
get方法,返回 轨道和该轨道上的物体 的map类型集合 - public L getCenter();
get方法,返回轨道系统的中心物体。 - public boolean removePhy(E e);
删除制定的轨道物体,删除的意义包含:轨道上的该物体,轨道物体总集合中的该物体,该轨道物体和其他物体包括轨道物体与中心物体的所有关系。 - public boolean removeTrack(Track t);
删除指定的轨道。其意义包含:删除改革轨道,删除该轨道上的所有物体 和 这些物体所具有的和其它物体的关系 - public boolean removeRelation(E point);
删除中心物体和指定轨道物体的关系。
3.3.2 实现类ConcreteCircularOrbit<L,E>
该类是implements的CircularOrbit<L,E> 类。
方法上一部分已经介绍了。
区别是,实现抽象方法时,添加了5个域。
- private Set thePhysical=new HashSet();
用来保存所有的轨道物体,没有进行轨道区分,方便便利查询。 - private Map<Track,Set> theTracks=new HashMap<Track, Set>();
用来保存轨道,和在相应轨道上的轨道物体。 - privateSet<Relation<L,E>>theCenRelations=newHashSet<Relation<L,E>>();
用来保存所有中心物体和轨道物体的关系。 - privateSet<Relation<E,E>>thePhyRelations=newHashSet<Relation<E,E>>();
用来保存所有轨道物体之间的关系。 - private L theCenter=null;
中心物体。
3.4 面向复用的设计:Track
针对 三个轨道系统,全部抽象为带个逻辑半径的物体。所以track类三者通用。只需添加radius域,还有get方法即可。针对实际应用情景,又添加了一个改动逻辑半径的方法。此方法便于在删除轨道操作时,实时完成对其他轨道逻辑半径的影响。例如,删除了2号轨道,那么3号轨道就变成了2号,之后以此类推,方便可视化绘图。
3.5 面向复用的设计:L
中心物体L,设计为了抽象类CentralObject,同时设置域nameString作为中心物体的名称(不一定用得到)。 设置了构造方法,和域的get方法(进行了防御性拷贝)。最后设置了重写equals的抽象类,便于之后的比较。接下来是实现类。
- Game
作为trackgame的中心物体存在,虽然trackgame理论上没有中心物体,但我抽象出了这个东西作为中心物体存在,其记录的时比赛类型,即100,200,400米比赛。所以域为int stytle。同时创建了构造方法,get方法,重写了equals方法。 - Element
作为atomstructure的中心物体。完全继承了central object,无需再添加其他的域。继承构造方法,重写equals方法就完事了。 - CentralUser
作为Social Network Circle的中心物体(其实和轨道物体属性完全相同,我也很想直接不写它了,但如果这样,就没有抽象类存在的必要了)。域:int age,string sex,int mk=0;分别作为年龄,性别,和潜在的编号,方便后来的求取逻辑距离。然后写了构造方法,相应的get方法。
3.6 面向复用的设计:PhysicalObject
恕我直言,我所选取的三个轨道系统的轨道物体,实在没啥共性可言(我硬是写成了抽象类)。域设置为num,表示该物体存在的数量。这个域在赛跑和社交圈里是没有用的,但是可以在电子系统中用到。然后创建了构造方法,和equals重写的抽象方法。以下是继承实现类。 - Athlete
按照要求设置了姓名,编号,国家,年龄,最佳成绩的域。设置了相应的get方法,同时重写了equals方法。 - Electron
按照手册的要求,同轨道上的电子是没有任何区别的,所以一个轨道上只需存在一个电子,而这个电子记录了在这条轨道上有多少个相同的电子即可。所以抽象类中设置的num就用到了。 - Friend
按照要求设置了和CentralUser一样的域,但便于绘图,又加入了坐标域。提供了相应的get方法,重写了equals方法。
3.7 可复用API设计
所选取的三个轨道系统,只有社交关系圈的物体之间会有联系,所以获取逻辑距离和物理距离的api只针对了社交关系圈系统。逻辑距离和物理距离的求取全部采用了dijkstra算法。由于写的比较粗糙,运行时会非常慢。
获取系统熵值的api则是直接在系统里实现了,比在这里实现要简单好多啊。
针对getDifference,设计了Difference类,域为两个string类型的arraylist,用来记录两个轨道系统各自的特殊之处。然后重写了toString方法,便于打印阅读。 而对getDifference的实现则是相当简单,两个轨道系统取出对应的轨道,一条轨道一条轨道的进行比较。
3.8 图的可视化:第三方API的复用
可视化主要用到了JFrame,JPanel,JTextField,JTextArea等API(貌似都是jdk自带的api),方法也很重复,jframe来构建窗口,重写jpanel的paint方法来进行画图。由于三个应用所要绘制的的轨道不太相同,所以写了三个helper方法(不要怪我,我真的不知道这三个怎么公用一个visualize)。除了社交关系圈的轨道物体采用了随机轨道位置,其它皆是均分。
3.9 设计模式应用 - 采用抽象工厂方法,用工厂的静态方法来实例化相应的对象。比如在中心物体和轨道物体的创建上。
- 同上。
- 随机遍历,按照轨道的逻辑半径从小到大。
- 将所有方法放进一个方法中,调用api时挨个输出结果。
- 随机排序,顺序排序,并在窗口上打印出排完序的结果。
3.10 应用设计与开发
显示一个总的功能选择窗口
3.10.1 TrackGame
点击trackgame后,首先选择要输入的文件
,然后就会显示比赛图
还有功能选择窗口
选择排序的话就会显示排序结果。
在右侧提供了交换选手的功能选择。
3.10.2 AtomStructure
点击后和上面的一样,输入文件窗口
然后显示轨道图和功能选择
3.10.3 SocialNetworkCircle
社交网络相同,这里就放一下成果图就ok了
不同的是,电子系统的电子分布是均匀的,而社交关系圈上的朋友则是在该轨道上的位置随机的。
3.11 应对应用面临的新变化
以下各小节,只需保留和完成你所选定的应用即可。
3.11.1 TrackGame
在图像上每条轨道显示了四个运动员,排序列表也增加了每条赛道上的运动员情况。就不再放图了。
3.11.2 AtomStructure
直接重建了element类,增加了质子和中子数。
3.11.3 SocialNetworkCircle
(我一开始建立的就是单向关系)。所以针对反向的输入直接就忽视了。
(此外,medium规模的文件,有好几个tie=0的关系)。
3.12 Git仓库结构
请在完成全部实验要求之后,利用Git log指令或Git图形化客户端或GitHub上项目仓库的Insight页面,给出你的仓库到目前为止的Object Graph,尤其是区分清楚312change分支和master分支所指向的位置。
4 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
日期 时间段 计划任务 实际完成情况
5.2 整天 能写多少是多少 还ok
5.3 整天 能写多少是多少 Ok
5.4 整天 完成部分可视化 完成
5.5 整天 完成剩下部分,spec,test,ri,af等 完成
5.6 3.00pm-6.00pm 写完报告 完成
5 实验过程中遇到的困难与解决途径
遇到的难点 解决途径
可视化完全不会
上csdn学习,慢慢摸索,然后学会了
泛型的传递问题
直接写三个方法就不用考虑这个了
命令行输入和可视化界面冲突,必须关闭一个另一个才能用
把命令行输入的功能写成按钮,加入到可视化界面中就OK了
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
合理规划实验的时间,这个51假期,就51当天玩了一天(而且还是内心比较忐忑的完),其他时间全部在写实验,除了吃饭和上厕所就没出过宿舍。还有就是设计模式用的特别生疏,甚至不知道该怎么用,导致程序的总体结构比较乱。可视化真的有趣,这是我上这门课感到真正有趣的地方了(果然我想去搞第九艺术)。总之学习到了非常多的操作,希望降低下实验难度和任务量。
6.2 针对以下方面的感受
(1) 重新思考Lab2中的问题:面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?本实验设计的ADT在五个不同的应用场景下使用,你是否体会到复用的好处?
Adt的话只需要考略所要求的功能与需求,但是面向具体场景的话,就要自己去提炼出场景的共性来设计一套adt。说实话,这次试验我没怎么感受到复用的好处,看似都是轨道系统,其实差距挺大的,很多时候adt里的方法都是为某一特定的场景设计的,这种方法没有复用可言。
(2) 重新思考Lab2中的问题:为ADT撰写复杂的specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后的编程中坚持这么做?
维护程序的安全性,你总不能希望自己的程序很简单就被别人给黑了吧。其实我还是愿意这么做的,但是能不能有一些af,ri的标准例子,每次写的都云里雾里的,可能是我没好好听课而且太菜了吧,
(3) 之前你将别人提供的API用于自己的程序开发中,本次实验你尝试着开发给别人使用的API,是否能够体会到其中的难处和乐趣?
没体会到乐趣,倒是感觉到了很多难处,特别是泛型的处理,这个我是不会,所以api写的特别冗余,网上查到的方法一大长串,看的有点懵,就没有用。
(4) 在编程中使用设计模式,增加了很多类,但在复用和可维护性方面带来了收益。你如何看待设计模式?
肯定是好的,但是我不太会用。还需要更加认真的去学习啊,必可活用于下一次。
(5) 你之前在使用其他软件时,应该体会过输入各种命令向系统发出指令。本次实验你开发了一个解析器,使用语法和正则表达式去解析输入文件并据此构造对象。你对语法驱动编程有何感受?
挺麻烦的,但是用起来很高效,而且感觉整个层面都上升了。但是一些时候要考虑的情况特别多,正则表达式会写的很长。匹配了后还要进行额外的处理,也挺麻烦的。
(6) Lab1和Lab2的大部分工作都不是从0开始,而是基于他人给出的设计方案和初始代码。本次实验是你完全从0开始进行ADT的设计并用OOP实现,经过三周之后,你感觉“设计ADT”的难度主要体现在哪些地方?你是如何克服的?
共性的提取。克服的方法…硬上。
(7) 你在完成本实验时,是否有参考Lab4和Lab5的实验手册?若有,你如何在本次实验中同时去考虑后续两个实验的要求的?
没有。
(8) 关于本实验的工作量、难度、deadline。
工作量太大了,难度适中(对比工作量,我感觉不时进行acm式的作业更有趣些),deadline幸好延后了一周,要不然就和考试撞了。所以我是希望避开考试,往后顺延的。
(9) 到目前为止你对《软件构造》课程的评价。
好难,感觉比csapp还难啊。学到的东西还是特别多的,不合理的地方我也没有太在意,希望以后多多改善吧。
上一篇: java中equals的理解