5/1/2019 update:没有考虑Lab4 和Lab5;GUI实现有待改进。
5/5/2019 update:正则表达式错误修改
5/18/2019 update:Atom-RE 再修改
首先请列出你要完成的具体应用场景(至少3个,1和2中选一,3必选,4和5中选一,鼓励完成更多的应用场景)。
- TrackGame
- AtomStructure
- SocialNetworkCircle
分析你所选定的多个应用场景的异同,理解需求:它们在哪些方面有共性、哪些方面有差异。
共性:
- 需要轨道系统中基本存在的对象,包括轨道、中心物体、轨道物体。其中物体都不考虑绝对位置。轨道都为圆形。
- 都需要完成的功能有:添加/删除轨道,在某一轨道上添加/删除物体,获得轨道系统的熵值,获得逻辑距离,比较两个同类型轨道系统的差异,检查轨道系统是否合法,可视化。
差异:
- TrackGame需要构造多个轨道系统,而其他两个只需要从文件中读入一个,需要编排。
- TrackGame需要实现编排策略,需要实现对轨道物体交换组/轨道系统。AtomStructure轨道物体都是值相同的对象,需要实现物体跃迁。SocialNetworkCircle中需要实现物体关系及对应操作,需要计算信息扩散度。
以下分别是三个应用的在输入处理中设计的正则表达式:
TrackGame:
AtomStructure:
SocialNetworkCircle:
(socialTiePattern最后一项没有排除0,需要另加判断)
对于在文件中读入的每一行,尝试用不同的pattern进行匹配并进行对应的处理(包括split),如果不能匹配则抛出运行时异常MyExp(自定义异常)。
其中SocialTie的正则表达式中用到了?:代表该括号是一个非捕获组,对于有多个括号的捕获情况,捕获顺序是从左到右,从外到内(嵌套)。
-
- 面向复用的设计:CircularOrbit<L,E>
类的域:
域名 | 作用 |
L centralObject | 中心物体 |
Map<Track,List<E>> physicalObjectMap | 轨道->轨道上物体的映射 |
List<Relation<L,E>>relOfCobj2TraObj | 中心物体与其朋友的关系 |
Map<E,List<Relation<E,E>>> relOf2TraObjs | 轨道物体与周围朋友的关系 |
方法以及实现:
方法名 | 方法实现 |
Public Boolean addTrack(Track newTrack) | 向physicalObjectMap中添加新轨道 |
Public Boolean removeTrack(Track rmTrack) | 从physicalObjectMap中删除轨道,轨道上物体随之被删除,调用removePhysicalObject。 |
Public void addCentralObject(L co) | 添加中心物体 |
Public void AddPhysicalObj2Track(E po,Track tk) | 向轨道tk上添加新物体po,修改relOf2TraObjs |
Public void removePhysicalObject(E po) | 在轨道系统中删除轨道物体po,需要在关系表中删除所有与之相关的关系 |
Public void addRelationOfCentralObj2TrackObj(L co,E po,double weight) | 向relOfCob2TraObj中添加关系 |
Public void remove RelationOfCentralObjs2TraObj(L eo,E po) | 在relOfCob2TraObj中删除该关系。 |
Public boolean addRelationOf2TrackObs(E po1,E po2,double weight) | 在relOf2TraObjs添加该关系 |
Public Boolean removeRelationOf2TrackObs | 在relOf2TrackObs中删除该关系 |
Public void transit(E oldObj,E newObj,Track t) | 将原来的轨道物体oldObj(Immutable)修改基本信息后生成的新物体newObj放到轨道t上。 |
Public void move(E oldObject,E newObject) | 将原有的轨道物体oldObject修改基本信息为新的轨道物体newObject。 |
Public double getObjectDistributionEntropy() | 获取轨道系统的熵值,每一条轨道上的物体数目/轨道系统所有物体数目作为p,使用entropy=-sigma(pi*log2(pi))公式计算轨道系统熵值。 |
Public int getLogicalDistance(E e1,E e2) | 使用BFS算法计算e1和e2之间的逻辑距离。 |
Public Difference getDifference(CircularOrbit<L,E> that) | 获得自身轨道系统与同类型轨道系统that之间的系统差异。获得两者经过排序之后的轨道(这里的轨道比较按照由内向外因此比较而不是按照半径相等对应比较),将进行比较的两轨道传入Difference对象中,交给Difference对象处理。最后返回Difference对象。 |
Public Boolean checkOrbitAvailable() | 检查系统是否合法,直接返回true交给具体应用系统进行重写。 |
Public Iterator<E> iterator() | 返回iterator迭代器。 |
注意到实验要求中的文件读入是不符合本实验中三个应用的共性的,因为TrackGame需要读入多个轨道系统,于是另设计构造类分别为TrackGame,AtomStructure,SocialNetworkCircle,负责读入文件,调用builder构造轨道系统(因此构造类中包含具体轨道系统的引用),负责作为GUI与Orbit轨道系统中的桥梁(获得Orbit基本信息,响应GUI事件,刷新GUI显示信息)。
-
- 面向复用的设计:Track
Immutable类。只有一个radius域。
方法:
getter,静态工厂方法getInstance,compareTo(Comparable接口),equals,hashCode。
其中,覆盖equals方法,Track使用Radius判断两个Track是否相等。
构造CommonObject作为CentralObject和PhysicalObject的父类。其中包括obName与pos分别代表物体名称以及物体位置,Position是Immutable类型。
方法:getter,drawGraphics,hashCode,toString
声明:Public void drawGraphics(Graphics g,GraphicsPainter painter):接受Graphics类与画笔信息类在g上根据画笔信息画出物体,所谓画笔信息类是一个mutable类,承载物体中心在g上的位置、物体绘制颜色、字体信息。在物体类中声明绘制方法是想将具体绘制方法委托到具体的类,而不是通过获取物体信息然后统一绘制。
Immutable对象类。CentralObject继承自CommonObject。
方法:getter,equals
-
- 面向复用的设计:PhysicalObject
Immutable类,继承自CommonObject。(没有设计为抽象类)
方法:equalsObject,compareTo(Comparable接口)
声明:1)public boolean equalsObject(Object obj),比较当前object与obj是否值相等,这里不覆盖equals,equals依旧是通过内存地址判断相等。
-
- 可复用API设计
- 计算轨道系统熵值。在ConcreteCircularOrbit中已经具体实现。
- 获取最短逻辑距离。在ConcreteCircularOrbit中已经具体实现。
- 获取物理距离:因为在三个应用中不考虑物理位置,所以不予实现。
- 计算两个多轨道系统之间的差异:
在ConcreteCircularOrbit中我们将两个对应的轨道物体集合添加到Difference对象中。下面声明Difference的类设计。
每一对比较的轨道,各自形成集合且只保留各自轨道上独有的轨道物体(去除交集,这里的比较使用equalsObject进行值比较),通过两个集合构造trackDifference对象,一个轨道系统的Difference由多个trackDifference构成。在trackDifference中提供toString方法将差异转化为字串,需要注意的是,如果两个集合都为空则说明两轨道上物体完全相同,这时候不输出“物体差异”。
-
- 图的可视化:第三方API的复用
本实验中使用Swing实现可视化功能。同时,在简单的轨道系统可视化基础上,添加了一部分简单控件用于优化交互体验。GUI如图1-4(图4显示了实现了在添加新物体时的GUI面板设计,验收的时候出了点问题)
图1. TrackGame轨道系统GUI实现
图2. AtomStructure轨道系统GUI实现
图3.SocialNetwork轨道系统GUI实现
图4. TrackGame轨道系统——添加新轨道物体功能面板
GUI实现思路:
- 使用IDEA插件JFormDesigner进行UI布局,所谓UI布局是为了设计各种控件(Button,ComboBox,Label等)在面板上的位置,将一个命名为drawPanel的JPanel放在左侧用来承载轨道系统。
- 对于每一个应用类,实现visualizeContentPanel方法,在这个方法中,构造并返回一个JPanel,在该JPanel中重写paint方法,在paint中根据当前Orbit的具体信息绘制当前轨道系统。visualizeContentPanel是暴露给CircularOrbitHelper的visualize使用的,在其中调用visualizeContentPanel方法获得JPanel只需要将这个将JPanel添加到一个JFrame中就可以显示该轨道系统。
- 对于每一个应用类,实现visualize(JPanel panel)方法,该方法将visualizeContentPanel中获得到的Jpanel添加到panel中。这个方法是暴露给像TrackGame这样的构造类的,在构造类中获得面板上的drawPanel引用,将drawPanel传入到应用类的visualize方法中即可显示轨道系统。之所以要这样设计是因为首先面板上不只有轨道系统还有很多信息交互的控件,在其中drawPanel只是用作布局占位用,可以看做容器,在Swing中绘图得通过重写paint实例化一个JPanel类来实现。
- 布局类(extends Jpanel)。使用JFormerDesigner可以通过可视化的方法生成一个布局类(布局可参考图1-4),在本次实验中,三个应用所实现的都是继承自JPanel的布局类,分别为TrackGamePanel,AtomStructurePanel,SocialNetworkCirclePanel,为布局类添加构造函数,传入构造类的引用。为了实现面板交互功能,添加事件监听器,包括对于不同控件的点击、选择等事件监听,在事件监听的回调函数中,调用构造类中的方法响应事件。
- 构造类。布局类在构造类中被创建,构造类传入引用。在事件响应中,构造类操作调用具体的应用类获得显示信息,然后将信息传入布局类中,布局类接受到信息后刷新控件内容。
GUI实现缺点:
布局类(目测)不能继承,所以需要分别实现三个布局类,所以需要分别实现三个构造类,冗余代码比较多。
没有实现错误处理,只能应对合法操作。(错误提示可以通过捕获操作异常MyExp进行弹窗来完成)
-
-
- 高级类
-
- Track,PhysicalObject等对象使用静态工厂方法实现,在类中设计getInstance方法获得对象。
- 对于ConcreteCircularOrbit的构造使用builder设计模式,设计抽象类ConcreteCircularOrbitBuilder,包括buildTrack,buildeObjects,buildRelation,通过传入的参数添加轨道系统组成。
每个具体应用类的Builder继承自ConcreteCircularOrbitBuilder,覆盖createConcreteCircularOrbit方法分别创建对应的轨道系统对象。
3)Iterator设计模式。设计MyIterator类,构造方法中传入轨道系统的PhysicalObjectMap(保护),首先按照轨道排序,之后按照轨道物体位置排序(因为不考虑轨道物体绝对位置,所以不予实现),在其中添加一个迭代下标,hashNext判断下标是否越界,next移动下标后返回值。
4)façade设计模式,实现API类。
-
-
- TrackGame
-
实现strategy设计模式。
设计接口类AssignmentStrategy,其中只有一个List<Map<Track,List<Runner>>> assign(List<Track> tracks,List<Runner> runnerList)声明。
分别实现具体策略类,简单编排SimpleStrategy,随即编排RandomStrategy,按bestscore排序编排SortedScoreStrategy。具体类中实现assign函数。
-
-
- AtomStructure
-
实现Memento设计模式管理电子跃迁的状态。
设计ElectronTransitMemento类,保存电子轨道跃迁信息,分别保存跃迁电子electron,源轨道fromTrack,目标轨道toTrack。
设计ElectronTransitCareTaker类,负责保存所有的动作列表,回退历史信息(返回删除点之后的所有操作列表)。回退动作先从CareTaker类中获得删除点之后的所有历史信息,然后传入轨道系统中反方向执行操作。
-
-
- SocialNetworkCircle
-
不需要实现设计模式
功能1:分别将划分轨道系统和轨道的任务委托给RandomStrategy与SortedScoreStrategy完成编排任务。
功能2:调整比赛方案,输入两个运动员的名称(这里假定了每个运动的名称都各不相同),调整轨道:调用在某一轨道上删除/添加一个物体的函数即可完成操作;调整轨道系统:首先需要找到各自的轨道系统、轨道,然后在其中删除目标物体,然后将两个物体分别添加到对方的轨道系统的轨道上。
判断合法性:按照要求实现。
功能:模拟电子跃迁。调用ConcreteCircularOrbit中实现的transit函数即可。
判断合法性:无。
功能1:从社交关系日志中恢复结构,首先将所有的输入信息读入,这时候我们得到了中心节点,与中心节点相邻的节点,节点之间的关联信息,在这个图上进行BFS,BFS的起始节点集合是所有与中心点相邻的节点,于是我们就可以获得哪些节点与中心节点不相邻(删去),各自的节点应该处于哪一条轨道上。之后调用Builder构造轨道系统即可。
功能2:计算第一条轨道上的亲密度因素:这里我们定义第一层轨道上的物体为V,其他物体为U,记v->u路径上紧密度的乘积为val(v,u),则v的扩散度为其所有能到达的物体u’的val(v,u’)之和。使用BFS,这里BFS一次的源点为一个第一层轨道上的物体,对每个第一层轨道上的物体都进行一次BFS。
功能3:增加/删除一条社交关系。增加删除关系可以直接调用ConcreteCircularOrbit中实现了的函数,不过考虑到关系改变会引起图的结构的改变(有的节点需要删除,有的节点需要改变所处的轨道),需要调用adjustFriendLocation来调整整个physicalObjectMap,这里采用的(暴力)方法是重复功能1中的BFS过程,重新计算所处轨道,然后删除不能连通的节点。
功能4:计算逻辑距离。调用ConcreteCircularOrbit中的getLogicalDistance即可。
对于应用三,删除轨道上的物体同样会引起图结构的改变,只需要调用ConcreteCircularOrbit中方法后重新调整图结构即可。
判断合法性:按照要求实现。
4人一个轨道:添加编排策略RelayRaceStrategy,每个轨道分配4个人。修改visualizeContentPanel方法一个轨道上显示全部的人。
修改后如图5.
图5 调用RelayRaceStrategy之后编排
原子核表达为多个质子和多个中子的组合:设计中子质子类,更改AtomCore,添加中子质子列表。修改AtomCore,覆盖drawGraphics方法,改一下AtomCore的显示字符串为多少个中子质子的组合。
具体显示如图6。
图6. 修改之后显示原子核组成
为关系增加方向性:在原来的实现中,无向边使用两条有向边表示,这里只需要改一下,添加/删除关系的时候只需要操作一条边即可。
忽略边:在读入边的时候,如果存在轨道物体向中心点的边则不操作,然后将其他所有的边加入,这里当然也包括了外层轨道到内层轨道的边,但是这里我们保留它,因为从实际应用角度出发,虽然一条边是从外层轨道到内层轨道的,但是在添加/删除关系之后这条边也可能变成内到外的边。
如何忽略?这里我们求出所有点到中心点的距离,根据距离即可判断内外(也可以求出所在的轨道-更简),每次更改关系结构之后需要重新求一遍距离,所以将求距离操作设计在adjustFriendsLocation中。
忽略影响:修改visualizeContentPanel,不显示外到内的边。修改求扩散度的操作,忽略所有外到内的边。但是如果两点之间是外到内的边,两者依然是相连的关系,这点在面板上的删除边功能上有所体现。
图7.修改之后的SocialNetworkOrbit(解释:在删除关系中有FrankLee->DavidChen的一条边,但是因为这条边是由外到内的所以在轨道系统图上被忽略了)
我是迷人的小尾巴
以下外链,利益相关,欢迎浏览ε≡٩(๑>₃<)۶ :