BUAA-OO-Unit3-单元总结
BUAA-OO-Unit3-单元总结
一、测试思路
本单元我没有使用Junit,测试方面主要依靠生成数据进行对拍。
理论上,只需要在生成数据时考虑到每一种可能的情况,即可保证数据的覆盖率。(由于有大佬写了数据生成器,因此我就只需要跟其对拍就行了)
二、架构设计
本单元设计到的图论算法有:最小生成树、单源最短路。同时,在增加Person和查询Block的时候很自然地能用到并查集来存储数据。
图的存储
在JML规格中,Person中已经有Acquaintance的属性了,因此自然而然地就是采用邻接表的图存储模式。
需要注意的是,在Network中存储的时候,为了性能和优化方便。我新引入了一个泛型类Dsu
维护策略
在很多地方,我们都只需要进行一次操作就能够知道查询的结果,这个时候可以单独维护变量作缓存操作,达成在查询的时候复杂度为O(1)。
例子:如查询年龄方差的指令(qgav)。需要算
展开得,
所以只需维护两个变量,即可计算出年龄方差。
图论算法
最小生成树:注意并查集优化即可,个人用kruskal算法
单源最短路:注意堆优化即可,个人用dijkstra算法
三、Bug分析
个人三次作业在中强互测中均未出现bug。
hack到得bug均是时间复杂度的问题。
第一次作业:qbs超时
第二次作业:qgav,qgvs超时
第三次作业:未进行hack
四、Network扩展
以下三个方法分别是:
发送广告、生产商生产产品、发送购买消息:
/*@ public normal_behavior
@ requires containsMessage(id) && (getMessage(id) instanceof Advertisement);
@ assignable messages;
@ assignable people[*].messages;
@ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1 &&
@ (\forall int i; 0 <= i && i < \old(messages.length) && \old(messages[i].getId()) != id;
@ (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
@ ensures (\forall int i; 0 <= i && i < people.length && !getMessage(id).getPerson1().isLinked(people[i]);
@ people[i].getMessages().equals(\old(people[i].getMessages()));
@ ensures (\forall int i; 0 <= i && i < people.length && getMessage(id).getPerson1().isLinked(people[i]);
@ (\forall int j; 0 <= j && j < \old(people[i].getMessages().size());
@ people[i].getMessages().get(j+1) == \old(people[i].getMessages().get(j))) &&
@ people[i].getMessages().get(0).equals(\old(getMessage(id))) &&
@ people[i].getMessages().size() == \old(people[i].getMessages().size()) + 1);
@ also
@ public exceptional_behavior
@ signals (MessageIdNotFoundException e) !containsMessage(id);
@ signals (NotAdvertisementException e) !(getMessage(id) instanceof Advertisement);
@*/
public void sendAdvertisement(int id) throws
MessageIdNotFoundException, NotAdvertisementException;
/*@ public normal_behavior
@ requires contains(producerId) && (getPerson(producerId) instanceof Producer);
@ assignable getProducer(producerId).productCount;
@ ensures getProducer(producerId).getProductCount(productId) ==
@ \old(getProducer(producerId).getProductCount(productId)) + 1;
@ also
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e) !contains(producerId);
@ signals (NotProducerException e) !(getPerson(producerId) instanceof Producer);
@*/
public void produceProduct(int producerId, int productId) throws
PersonIdNotFoundException, NotProducerException;
/*@ public normal_behavior
@ requires containsMessage(id) && (getMessage(id) instanceof BuyMessage);
@ requires (getMessage(id).getPerson1() instanceof Customer) && (getMessage(id).getPerson2() instanceof Advertiser);
@ assignable messages;
@ assignable getMessage(id).getPerson1().money;
@ assignable getMessage(id).getPerson2().messages, getMessage(id).getPerson2().money;
@ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1 &&
@ (\forall int i; 0 <= i && i < \old(messages.length) && \old(messages[i].getId()) != id;
@ (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
@ ensures (\forall int i; 0 <= i && i < \old(getMessage(id).getPerson2().getMessages().size());
@ \old(getMessage(id)).getPerson2().getMessages().get(i+1) == \old(getMessage(id).getPerson2().getMessages().get(i)));
@ ensures \old(getMessage(id)).getPerson2().getMessages().get(0).equals(\old(getMessage(id)));
@ ensures \old(getMessage(id)).getPerson2().getMessages().size() == \old(getMessage(id).getPerson2().getMessages().size()) + 1;
@ ensures (\old(getMessage(id)).getPerson1().getMoney() ==
@ \old(getMessage(id).getPerson1().getMoney()) - ((BuyMessage)\old(getMessage(id))).getMoney() &&
@ \old(getMessage(id)).getPerson2().getMoney() ==
@ \old(getMessage(id).getPerson2().getMoney()) + ((BuyMessage)\old(getMessage(id))).getMoney());
@ also
@ public exceptional_behavior
@ signals (MessageIdNotFoundException e) !containsMessage(id);
@ signals (NotBuyMessageException e) !(getMessage(id) instanceof BuyMessage);
@ signals (NotCustomerException e) !(getMessage(id).getPerson1() instanceof Customer);
@ signals (NotAdvertiserException e) !(getMessage(id).getPerson2() instanceof Advertiser);
@*/
public void sendBuyMessage(int id) throws
MessageIdNotFoundException, NotBuyMessageException, NotCustomerException, NotAdvertiserException;
五、心得体会
本单元相比一、二单元难度小很多,只要在第三单元的第一次作业学会了如何读JML规格,这个单元就很简单了。(也因此就会觉得本单元的内容有点单薄枯燥,建议给学弟学妹们加点难度。)
本单元重点在如何阅读或者编写JML规格,个人感觉就是与离散数学的结合。
同时,我们所用的规格是较为基础的JML,如果用更加高级的JML最为扩展阅读会不会更好?
最后,这个单元也给我们开发软件提供了一个未来方向——能不能通过规格实现代码自动化生成?能不能通过规格进行自动化测试?