OO_Lab2

一、单元内容

本单元内容为规格化设计,即通过参考已经完成的JML描述实现一个社交网络相关功能。

本单元整体来说难度不大,但是却是我最惨的一次作业,所以本博客可能会主要谈一谈测试中的一些策略吧。

二、自测策略

1、白盒测试

即从JML出发针对各种情况构造测试数据,可以选用课程组推荐的JUnit单元测试框架来对每个函数进行测试。我也借此机会学习了一下JUnit的用法。

在构造测试数据的时候,可以充分利用JML规格来构造一些针对性的数据,比如看哪个方法JML较为复杂,可以针对这样的方法构造一些边界情况的数据,比如作业中的queryBlockSumgetValueSumqueryLeastConnectionsendIndirectMessage等操作,尤其是对于那些不能直接照着JML写,而是需要自己进行优化的方法进行着重测试,构造极端数据。

2、黑盒测试

也就是随机对拍,我个人还是觉得在本课程中随机对拍仍然是最好的调试方式,尤其是在本单元中。本人在本单元第三次作业的时候因为一些其他事情占用了一些时间,而且第二次作业未编写对拍,第三次作业编写对拍相对来说难度不低,因此未进行随机测试,只是进行了一些功能测试和单元测试,各项功能都正常,最后因为在编写异常时直接复制相同类型的类,结果忘了改前面的字符串,然后测试的时候没考虑到这部分,强测喜提30分。

三、架构设计

本单元的目标是要实现一个社交网络,主要包括NetworkMessageGroupPerson等类,本单元大部分代码都可以直接按照JML的逻辑完成,因此这些代码不涉及架构方面的问题。

在这里主要是列举一些特殊函数,这些函数要么JML并没有给出具体的实现逻辑,要么按照JML的逻辑可能会导致超时(CTLE)的情况。

1、queryBlockSum

JML提供了一个 \(O(N^2)\) 的做法,但是这无法满足复杂度的要求,观察代码可以看出它计算了所有 \(1\sim i-1\) 中和 \(i\) 不相连的 \(i\) 的个数,本质上也就是连通块个数,因此可以使用并查集来维护。

处于优化代码结构的目的,我将并查集单独分为一类,在其中实现了add(x)merge(x1,x2)union(x1,x2)getCountBlock等操作,降低了代码的耦合性。

2、queryLeastConnection

本函数的JML只描述了一个边的集合,即我们的答案具有什么样的特征,而对于如何求解则没有给出具体做法,观察这个边的集合会发现他是用最少的边权和把所有点连起来的方案,也就是最小生成树,考虑到复杂度的问题,我们可以使用堆优化的Prim算法来求解。

Prim我同样单独封装为一个类,实现了add(a,b,val)query(st)操作,在外层只需要直接调用即可。

3、queryGroupValueSum

这个从JML出发可以直接得到做法,但是这样的做法却会超时,因此正确的做法是在addRelationaddPersondelPerson时维护一个Group的答案,这样就将询问原本 \(O(N^2)\) 的复杂度转化为了修改时单次 \(O(N)\) 的复杂度。

4、sendIndirectMessage

与queryLeastConnection操作类似,它给出了一个点的集合,观察可以发现相邻两个点相连,也就是描述了路径的性质,而最终也就是求的最短路径,可以用堆优化Dijkstra解决。具体实现与Prim的实现类似。

四、性能问题与修复情况

性能问题上面已经描述了几个可能出现性能问题的操作最终是如何解决的。

本人自己的错误除了上述写错字符串错误外,在第二单元的Dijkstra实现也出现了错误,一是很简单的Dijkstra写错,二是没有考虑到一个连通块中只有一个点的情况。

这些错误归根到底还是没有进行充分的测试,本次出现的错误都很明显,基本都是由于粗心导致写错,也很容易改正,以后还是应该编写足够的随机测试,只能说吃一堑长一智了。

本人在房内hack出qgvs超时等情况,前面已经提过,再次不再赘述。

五、功能扩展

功能要求

假设出现了几种不同的Person

  • Advertiser:持续向外发送产品广告
  • Producer:产品生产商,通过Advertiser来销售产品
  • Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息
  • Person:吃瓜群众,不发广告,不买东西,不卖东西

如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等 请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格(借鉴所总结的JML规格模式)

扩展实现

AdvertiserProducerCustomer 实现 Person 接口,新增 AdvertisementMessage 类、BuyMessage 类,他们实现 Message 接口。AdvertisementMessage 类应保存 ProducerProductPrice 等信息。BuyMessage类应保存 Product 等信息。

求产品销售量

/*@ public instance model non_null Product[] products;
@ public instance model non_null Product[] productSales;
@*/ /*@ public normal_behavior
@ requires containsProduct(product);
@ ensures (\exists int i; 0 <= i && i < products.length;
@ products[i].getId() == product.getId() && \result == productSales[i]);
@ also
@ public exceptional_behavior
@ signals (ProductNotFoundException e) !containsProduct(product);
@*/
public int queryProductSales(Product product) throws ProductNotFoundException;

发布广告

/*@ public instance model non_null AdvertisementMessage[] advertisementMessages;
@*/ /*@ public normal_behavior
@ requires !(\exists int i; 0 <= i && i < advertisementMessages.length; advertisementMessages[i].equals(advertisement)) &&
@ containsProductId(advertisement.getProductId()) &&
@ (advertisement.getType() == 0) ==> (advertisement.getPerson1() != advertisement.getPerson2());
@ assignable advertisementMessages;
@ ensures advertisementMessages.length == \old(advertisementMessages.length) + 1;
@ ensures (\forall int i; 0 <= i && i < \old(advertisementMessages.length);
@ (\exists int j; 0 <= j && j < advertisementMessages.length; advertisementMessages[j].equals(\old(advertisementMessages[i]))));
@ ensures (\exists int i; 0 <= i && i < advertisementMessages.length; advertisementMessages[i].equals(advertisement));
@ also
@ exceptional_behavior
@ signals (EqualAdvertisementIdException e) (\exists int i; 0 <= i && i < advertisementMessages.length; advertisementMessages[i].equals(advertisement));
@ signals (ProductIdNotFoundException e) !(\exists int i; 0 <= i && i < advertisementMessages.length; advertisementMessages[i].equals(advertisement)) &&
@ !containsProductId(advertisement.getProductId());
@ signals (EqualPersonIdException e) !(\exists int i; 0 <= i && i < advertisementMessages.length; advertisementMessages[i].equals(advertisement)) &&
@ containsProductId(advertisement.getProductId()) &&
@ advertisement.getType() == 0 && advertisement.getPerson1() == advertisement.getPerson2();
@*/
public void advertise(AdvertisementMessage advertisement)
throws EqualAdvertisementIdException, ProductIdNotFoundException, EqualPersonIdException;

这里只是生成发布广告的Message,之后需要进一步sendIndirectMessage。

生产产品、购买产品的操作与此类似

添加偏好

/*@ public normal_behavior
@ requires !(\exists int i; 0 <= i && i < referenceProductId.length; referenceProductId[i].equals(product.getId()));
@ assignable referenceProductId;
@ ensures referenceProductId.length == \old(referenceProductId.length) + 1;
@ ensures (\forall int i; 0 <= i && i < \old(referenceProductId.length);
@ (\exists int j; 0 <= j && j < referenceProductId.referenceProductId; people[j] == (\old(referenceProductId[i]))));
@ ensures (\exists int i; 0 <= i && i < referenceProductId.length; referenceProductId[i] == product.getId());
@ also
@ public exceptional_behavior
@ signals (EqualProductIdException e) (\exists int i; 0 <= i && i < referenceProductId.length; referenceProductId[i].equals(product.getId()));
@*/
public void AddReference(Product product) throws EqualProductIdException;

六、总结反思

首先是编程思想方面,本单元通过学习JML相关知识以及课外的了解和分享,我了解了契约式编程等相关思想,对于其可靠、易于测试的优势有了一定理解,鉴于目前写的代码都比较短,了解这些思想对于之后编写大规模的项目肯定还是很有用处的。

然后是测试方面,我学会了如何用JUnit进行单元测试。本单元相对前两个单元难度不高,但是却出了很大的错误,之后还是应该更加注重数据的测试,尽可能自己设计覆盖率高的强测。

OO_Lab2总结博客的更多相关文章

  1. Android请求网络共通类——Hi_博客 Android App 开发笔记

    今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...

  2. 一步步开发自己的博客 .NET版(11、Web.config文件的读取和修改)

    Web.config的读取 对于Web.config的读取大家都很属性了.平时我们用得比较多的就是appSettings节点下配置.如: 我们对应的代码是: = ConfigurationManage ...

  3. 一步步开发自己的博客 .NET版(10、前端对话框和消息框的实现)

    关于前端对话框.消息框的优秀插件多不胜数.造轮子是为了更好的使用轮子,并不是说自己造的轮子肯定好.所以,这个博客系统基本上都是自己实现的,包括日志记录.响应式布局.评论功能等等一些本可以使用插件的.好 ...

  4. 【原】Github+Hexo+NextT搭建个人博客

    摘要 GitHub 是一个开源项目的托管网站,相信很多人都听过.在上面有很多高质量的项目代码,我们也可以把自己的项目代码托管到GitHub,与朋友们共享交流.GitHub Pages 是Github为 ...

  5. 我为什么要写LeetCode的博客?

    # 增强学习成果 有一个研究成果,在学习中传授他人知识和讨论是最高效的做法,而看书则是最低效的做法(具体研究成果没找到地址).我写LeetCode博客主要目的是增强学习成果.当然,我也想出名,然而不知 ...

  6. 博客使用BOS上传图片

    1.博客平台的选定 从大学开始做个人主页算起,最开始是使用html,CSSS写简单的页面,后面大学毕业之后接触到了WordPress,就开始用WordPress搭建网站.现在还维护着一个农村网站.ht ...

  7. 在jekyll模板博客中添加网易云模块

    最近使用GitHub Pages + Jekyll 搭建了个人博客,作为一名重度音乐患者,博客里面可以不配图,但是不能不配音乐啊. 遂在博客里面引入了网易云模块,这里要感谢网易云的分享机制,对开发者非 ...

  8. iOS controller解耦探究实现——第一次写博客

    大学时曾经做过android的开发,目前的工作是iOS的开发.之前自己记录东西都是通过自己比较喜欢的笔记类的应用记录下了.直到前段时一个哥们拉着我注册了一个博客.现在终于想明白了,博客这个东西受众会稍 ...

  9. 中文 iOS/Mac 开发博客列表

    中文 iOS/Mac 开发博客列表 博客地址 RSS地址 OneV's Den http://onevcat.com/atom.xml 一只魔法师的工坊 http://blog.ibireme.com ...

  10. 企业shell面试题:获取51CTO博客列表倒序排序考试题

    #!/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin HTMLFILE=/home/oldboy/ht ...

随机推荐

  1. vue-awesome-swiper使用中的一些问题

    项目中使用了vue-awesome-swiper,发现autoplay不能用.网上找了半天,说是版本问题.最后在main.js中添加以下代码解决. import VueAwesomeSwiper fr ...

  2. 三步建立自己域名的主页,Github Pages功能简明手册

    [task]把自己的页面上传到git上,用github pages功能托管网页. 准备工作: 1.自己的网页文件 2.有个自己的git账号 3.下载安装git.下载地址https://git-scm. ...

  3. 排序算法 | JS

    1.冒泡排序 function bubbleSort(arr,order){ let len = arr.length-1,flag=true for(let i=0;(i<len)&& ...

  4. idea 导入项目之后,只显示项目文件,不显示项目结构

    导入项目之后,只显示项目文件,不显示项目结构 解决方法 1.点击file->project structure..->Modules 点击右上角+加号 ->import Module ...

  5. Entity Framework Core 的 SQL 日志记录

    日志配置通常由 appsettings {Environment} .json 文件的 Logging 部分提供 . 若要记录 SQL 语句,请将 "Microsoft.EntityFram ...

  6. JS学习-常用的Web API

    web API web-api 分类 链接 描述 操作文档的API 操作document dom,html,svg 从服务器获取数据的API XMLHttpRequest XMLHttpRequest ...

  7. .NET在单台Windows2008下百万TCP连接测试

    测试客户端: 客户端程序建立TCP连接,发送一条几个字节的数据. 虚拟机8台,PC机8台,服务器1台. 设置MaxUserPort=60000,有一台机没有设置约在1.5万左右.最后因为差一点到100 ...

  8. Springboot实现文件上传下载功能

    一.文件上传 1. controller层 @RestController @RequestMapping(value = "/excel") public class Uploa ...

  9. WDA学习(21):WDA Popup,Message,Focus

    1.14 WDA Popup,Message,Focus WDA测试Popup,Message,光标Focus功能. 1.创建Component; COMPONENTCONTROLLER页签 Cont ...

  10. iOS加载动态自定义字体

    iOS加载动态自定义字体  NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDom ...