BUAA-OO-Unit3-单元总结

BUAA-OO-Unit3-单元总结

一、测试思路

本单元我没有使用Junit,测试方面主要依靠生成数据进行对拍

理论上,只需要在生成数据时考虑到每一种可能的情况,即可保证数据的覆盖率。(由于有大佬写了数据生成器,因此我就只需要跟其对拍就行了

二、架构设计

本单元设计到的图论算法有:最小生成树单源最短路。同时,在增加Person和查询Block的时候很自然地能用到并查集来存储数据。

图的存储

在JML规格中,Person中已经有Acquaintance的属性了,因此自然而然地就是采用邻接表的图存储模式。

需要注意的是,在Network中存储的时候,为了性能和优化方便。我新引入了一个泛型类Dsu来提供并查集的有关接口。同时也在Network中存储了所有的关系(边),能够在一定程度上优化。

维护策略

在很多地方,我们都只需要进行一次操作就能够知道查询的结果,这个时候可以单独维护变量作缓存操作,达成在查询的时候复杂度为O(1)。

例子:如查询年龄方差的指令(qgav)。需要算

\[\sum (age_i-\overline{age})^2 \]

展开得,

\[\sum (age_i-\overline{age})^2 = \sum age_i^2-2*\overline{age}\sum age_i +n*\overline{age}^2 \]

所以只需维护两个变量,即可计算出年龄方差。

图论算法

最小生成树:注意并查集优化即可,个人用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最为扩展阅读会不会更好?

最后,这个单元也给我们开发软件提供了一个未来方向——能不能通过规格实现代码自动化生成?能不能通过规格进行自动化测试?

posted @ 2022-06-05 15:35  CoolColoury  阅读(23)  评论(1编辑  收藏  举报