BUAA_OO_第三单元作业总结
BUAA_OO_第三单元作业总结
简述
本单元作业的关键之处,还是在于训练我们对于JML规格语言的理解,因而,对于我而言,本单元作业的设计构造其实并不难,难点还是在于如何利用JML规格提高代码质量,提高查找效率。
第一次作业
UML
性能问题和修复情况
在本次作业中,比较吃性能的是query_block_sum
指令。一开始,我采取的策略是给每个person
建立一个关系list
,将每个与其有关系的person
加入其中,但是在实际测试中,由于每次add_relation
之后都要更新每个person
的关系list
,不仅造成了性能的大量浪费,而且有重复、缺失的隐患,因而,在后期的修复过程中,我主要采取了并查集以及Cache缓存的机制来提升代码效率。
我在作业中的Cache实现其实很简单,主要在MyNetwork
中建立了俩个变量,一个boolean
型变量change用来储存当前图是否更新,一个int
型变量qbs
变量用来储存query_block_sum
指令查询结果。当图未更新,且已经通过query_block_sum
指令查询出来了结果则直接返回,否则执行查询代码并存储起来。
实际过程中,这样的机制对于重复查询的指令来说效果十分明显。
第二次作业
UML
BUG修复
这次作业最主要的问题,是由于我对Cache的一个设计错误。由于这个作业与上一次不一样,这次作业中存在多个复杂度较高的查找指令,而我只设置了一个boolean
型变量来表示图是否更新,没有考虑储存的指令结果是否更新,从而导致该变量对指令传达的信息错误,从而返回未更新的结果导致错误。
在后续的改进中,对于每个执行复杂度较高指令,我对于其储存的结果新增了一个标识位,用来表示其结果是否更新。
第三次作业
自测
在本单元中,我主要使用了JUnit来对代码的正确性进行快速测试,同时,我也自行构建了一些较为极端的数据,来测试代码对于极端数据的处理。但是,由于受到手动构造数据的限制,对于代码的性能以及查找效率方面的考虑不足,导致在后续的公测和互测中很容易因为超时而WA。
扩展任务
假设出现了几种不同的Person
- Advertiser:持续向外发送产品广告
- Producer:产品生产商,通过Advertiser来销售产品
- Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息
- Person:吃瓜群众,不发广告,不买东西,不卖东西
如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等 请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格(借鉴所总结的JML规格模式)
需要增加三个Advertiser
、Producer
、Customer
类继承Person
类,AdvertiseMessage
类继承Message
类;同时增加Product
类来储存产品的信息。
同时我们可以在Network
中增加ProductList
用来储存当前市面上的产品。
下面将简要介绍这几个类的核心行为。
makeProduct
:生产产品,Producer
生产产品,并加到ProductList
中。
/*@ public normal_behavior
@ requires (\exists int i; 0 <= i && i < people.length; people[i].getId() == id) &&
(getPerson(id) instanceof Producer) &&
(\exists int i; 0 <= i && i < productList.size; productList[i].getType == getPerson(id).getMakeProductType);
@ assignable getProduct(getPerson(id).getMakeProductType).count;
@ ensures productList.size() == \old(productList.size);
@ ensures (\forall int i; 0 <= i && i < \old(productList.size);
(\exist int j; 0 <= j && j < productList.size; productList[j].getType == \old(productList[i].getType)));
@ ensures getProduct(getPerson(id).getMakeProductType).count = \old(getProduct(getPerson(id).getMakeProductType).count) + 1;
@ also
@ requires (\exists int i; 0 <= i && i < people.length; people[i].getId() == id) &&
(getPerson(id) instanceof Producer) &&
!(\exists int i; 0 <= i && i < productList.size; productList[i].getType == getPerson(id).getMakeProductType);
@ assignable productList;
@ ensures productList.size() == \old(productList.size) + 1;
@ ensures (\forall int i; 0 <= i && i < \old(productList.size);
(\exist int j; 0 <= j && j < productList.size; productList[j].getType == \old(productList[i].getType)));
@ ensures (\forall int i; 0 <= i && i < \old(productList.size);
(\exist int j; 0 <= j && j < productList.size; productList[j].count == \old(productList[i].count)));
@ ensures (\exist int i; 0 <= i && i < productList.size; productList[i].count == 1);
@ ensures (\exist int j; 0 <= j && j < productList.size; productList[j].getType == getPerson(id).getMakeProductType);
@ public exceptional_behavior
@ signals (PersonIdNotFoundException e) !(\exists int i; 0 <= i && i < people.length; people[i].getId() == id);
@ signals (NotProducerException e) (\exists int i; 0 <= i && i < people.length; people[i].getId() == id) &&
!(getPerson(id) instanceof Producer);
@*/
public void makeProduct(int id) throws PersonIdNotFoundException, NotProducerException;
sendAdvertise
:发送广告。
/*@ public normal_behavior
@ requires containsMessage(id) && (getMessage(id) instanceof Advertise) && getMessage(id).getType == 1;
@ assignable people[*].messages, messages;
@ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1;
@ ensures (\forall int i; 0 <= i && i < messages.length;
(\exist int j; 0 <= j && j < \old(messages.length); messages[i].getId == \old(messages[j].getId)));
@ ensures (\forall int i; 0 <= i && i < getMessage(id).getGroup.getPeople.size;
getMessage(id).getGroup.getPeople[i].getMessage.size ==
\old(getMessage(id).getGroup.getPeople[i].getMessage.size) + 1);
@ ensures (\forall int i; 0 <= i && i < getMessage(id).getGroup.getPeople.size;
(\exist int j; 0 <= j && j < getMessage(id).getGroup.getPeople[i].getMessage.size;
getMessage(id).getGroup.getPeople[i].getMessage[j].getId() == id));
@ also
@ requires containsMessage(id) && (getMessage(id) instanceof Advertise) && getMessage(id).getType == 0;
@ assignable getMessage(id).getPerson2.messages, messages;
@ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1;
@ ensures (\forall int i; 0 <= i && i < messages.length;
(\exist int j; 0 <= j && j < \old(messages.length); messages[i].getId == \old(messages[j].getId)));
@ ensures getMessage(id).getPerson2.getMessage.size == \old(getMessage(id).getPerson2.getMessage.size) + 1;
@ ensures (\exist int i; 0 <= i && i < getMessage(id).getPerson2.getMessage.size;
getMessage(id).getPerson2.getMessage[i].getId() == id);
@ public exceptional_behavior
@ signals (MessageIdNotFoundException e) !containsMessage(id);
@ signals (NotAdvertisementException e) containsMessage(id) && !(getMessage(id) instanceof Advertisement);
@*/
public void sendAdvertise(int id) throws MessageIdNotFoundException, NotAdvertisementException;
saleProduct
:销售产品。
/*@ public normal_behavior
@ requires (exist int i; 0 <= i && i < productList.length; productList[i].getType == productType) &&
getProduct(productType).count > 0;
@ assignable getProduct(productType).count;
@ ensures getProduct(productType).count = \old(getProduct(productType).count) - 1;
@ ensures productList.size() == \old(productList.size);
@ ensures (\forall int i; 0 <= i && i < \old(productList.size);
(\exist int j; 0 <= j && j < productList.size; productList[j].getType == \old(productList[i].getType)));
@ public exceptional_behavior
@ signals (ProductTypeNotFoundException e) !(exist int i; 0 <= i && i < productList.length; productList[i].getType == productType);
@ signals (ProductNotHaveException e) (exist int i; 0 <= i && i < productList.length; productList[i].getType == productType) &&
getProduct(productType).count <= 0;
@*/
public void saleProduct(int productType) throws ProductTypeNotFoundException, ProductNotHaveException;
学习体会
这三次作业的JML真是层层递进,越到后面,JML规格代码就越多,也因此在第三次作业中,我就因为看花了眼,导致我在代码中埋下一个超级“地雷”,在强测中"砰"的一声,把我炸的人都麻了。
但是,随着学习的深入,我对于JML规格语言也有了一定的了解。在现代的实际生产中,一个优秀的程序必定是由多个人共同努力才能编写完成的,而一个人是不可能在短时间内就完成那成千上万行的代码而不出错的。如何协调代码的各个部分,使得代码能够完美的组合起来,JML设计规格就帮助我们解决了这个问题。通过逻辑来对代码进行束缚,可以使得我们在使用其的过程中并不需要考虑其具体实现,仅仅只需要考虑我们要给它什么,它会给我们什么就行,并需要考虑其会对于我们的其他数据有什么影响,因为一切都已经束缚好了。不过有些过程通过逻辑来描述是真的很复杂。