BUAA_OO_UNIT3
BUAA_OO_UNIT3
1.测试数据的准备
本单元的测试数据准备时,需要满足各个指令的前置条件,方法是自动生成并与他人对拍,关键是指令要覆盖全面,尽可能多。本人在对拍过程中发现一些很诡异的bug,例如有些bug体现在复杂度较高的方法输出有异常,但方法的逻辑并未出现问题,而是由于本人误用==
比较两个Integer的大小,导致出错,这在指令数较少的情况下无法测试出来。
2.架构设计
本单元作业的核心是实现了 一个多人聊天系统,主要的架构官方JML规格已给出,自己主要实现的就是Network类中几个关键的图算法。
容器选择
由于Person、Group等对象在Network中有互不相同的id,且大量方法是通过id对应到对象,因此容器均选择HashMap,保存id和对象的对应关系,节省查找时间。
private HashMap<Integer, Person> people;
private HashMap<Integer, Group> groups;
private HashMap<Integer, Message> messages;
图模型构建
三次作业中,主要是构建了Person之间的关系图,涉及的复杂度较高的方法有:
boolean isCircle(int id1, int id2)
:判断id1与id2之间是否可达。
int queryBlockSum()
:本质是查询图中最大连通分量的个数
int queryLeastConnection(int id)
: 本质是求出图中所有与id可达的人组成的最小生成树,并返回生成树的边权值之和。
int sendIndirectMessage(int id)
: 发送消息,并返回发送和接受消息双方的最短路径长度。
在第一次作业中,通过并查集简化queryBlockSum
和isCircle
方法的复杂度,在NetWork中新建两个属性:blocks
和depths
,类型均为HashMap<Integer, Integer>
,分别记录person节点的父子关系和深度。在addPerson
、addRelation
时对二者进行修改更新。
第二次作业中,利用kruskal算法实现最小生成树的查询。通过TreeSet<MyEdge>
保存Person关系图的边,MyEdge
保存两个Person节点以及他们之间的value
。选择TreeSet
保存边是为了缩短找最小边的时间。
第三次作业中,为实现最短路径算法,采用迪杰斯特拉算法+堆优化,通过java提供的PriorityQueue
实现堆优化。
异常处理
由于多个异常类的本质都是计数,为了实现代码复用,通过Counter
类作为异常类的静态属性,保存异常计数。
private static Counter counter = new Counter();
3.bug分析
三次作业在强测和互测中都没有任何bug,由于设计之初就考虑了性能问题,因此没有出现TLE等情况。
4.Network拓展
题目要求
假设出现了几种不同的Person
- Advertiser:持续向外发送产品广告
- Producer:产品生产商,通过Advertiser来销售产品
- Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息
- Person:吃瓜群众,不发广告,不买东西,不卖东西
如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等 请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格(借鉴所总结的JML规格模式)
NetWork中存在四种Person实例,
其中Advertiser可以发送广告给所有Customer。
Producer与特定Advertiser关联,销售给消费者产品,并有查询销售额方法
Customer内有一个关注的广告列表,保存其关注的广告。购买产品时给Advertiser发消息,通知对应的Producer。
下面选择发送广告、查询销量、
发送广告:Advertiser将广告发送给所有Customer
/*@ public normal_behavoir
@ requires containsAdvertisement(id);
@ assignable advertisements;
@ assignable customer[*].subscribledList;
@ ensures !containsAdvertisement(id) &&
@ advertisements.length == \old(advertisements.length) - 1 &&
@ (\forall int i; 0 <= i && i < \old(advertisements.length) && \old(advertisements[i].getId()) != id;
@ (\exists int j; 0 <= j && j < advertisements.length; advertisements[j].equals(\old(advertisements[i]))));
@ ensures (\forall int i; 0 <= i && i < customers.length; customers[i].subscribledList.length == \old(customers[i]).subscribledList.length + 1);
@ ensures (\forall int i; 0 <= i && i < customers.length;
@ (\exists int j; 0 <= j && j < customers[i].subscribledList.length;
@ customers[i].subscribledList[i].getId() == id));
@ ensures (\forall int i; 0 <= i && i < customers.length;
@ (\forall int j; 0 <= j && j < \old(customers[i]).subscribledList.length;
@ (\exists int k; 0 <= k && k < customers[i].subscribledList.length;
@ customers[i].subscribledList[k] == \old(customers[i].subscribledList[j]))));
@*/
public void sendAdvertisement(int id);
查询销量:查询producer的销量
/*@ public normal_behavoir
@ requires producers.contains(producerId);
@ assignable \nothing;
@ ensures \result == producers[producerId].getSaleValue;
@*/
public int querySaleValue(int producerId);
发送购买产品消息:customer经由advertiser给producer发送购买消息,producer将customer的id保存在purchaseInfo中。
/*@ public normal_behavoir
@ requires advertisers.contains(advertiserId);
@ requires consumers.contains(id);
@ assignable advertisers[advertiserId].getProducer().purchaseInfo;
@ ensures advertisers[advertiserId].getProducer().purchaseInfo.length == \old(advertisers[advertiserId].getProducer().purchaseInfo).length + 1;
@ ensures (\forall int i; 0 <= i && i < \old(advertisers[advertiserId].getProducer().purchaseInfo).length;
@ (\exists int j; 0 <= j && j < advertisers[advertiserId].getProducer().purchaseInfo.length;
@ advertisers[advertiserId].getProducer().purchaseInfo[j] == \old(advertisers[advertiserId].getProducer().purchaseInfo)[i]);
@ ensures (\exists int i; 0 <= i && i <= advertisers[advertiserId].getProducer().purchaseInfo.length;
@ advertisers[advertiserId].getProducer().purchaseInfo[i] == id);
@*/
public void purchase(int id, int advertiserId, int productId);
5.学习体会
本单元作业主要是通过阅读jml规格完成作业,用到的算法也是大一数据结构学过的有关图论算法。难度不是很大,但也培养了按规格写出优性能代码的能力,同时复习了图论重要的算法。