BUAA_OO_第三单元作业
BUAA_OO_UNIT3
1.测试数据的准备
对于核心方法(算法方法),主要还是基础功能测试,查找经典例题,将它改成我们题目的场景,进行测试。
对于其他方法,主要通过和其他同学对拍来发现自己对于题目理解的疏忽,进行改正。
2.架构设计
图模型构建和维护
本质上是将一个个MyPerson对象视为图中的节点,将Relation视为图的边,Relation的value视为边的权值,下面是几个主要方法。
isCircle
本质是判断两个点是否联通,采用了并查集优化。
采用了hashmap代替了数组。
merge时判断大小,保证并查集的深度不超过log(V)(V是点的个数)。
int queryBlockSum():
本质是查询图中最大连通分量的个数,因为做了并查集优化吗,所以可以写出如下的计算代码
public int queryBlockSum() { int cnt = 0; Set<Integer> people = blocks.keySet(); for (Integer person : people) { if (find(person, blocks, depths) == person) { cnt++; } } return cnt; }
queryLeastConnection
本质是求出当前点所在连通块的最小生成树,采用了Dijkstra算法,其中为了避免每一次都要排序的巨大开销,采用了来维护一个有序的边的集合,在使用时遍历这一个边的集合并辅以是否再一个连通块的判断来达到相同的效果。
sendIndirectMessage
本质是求两点之间的最短路径,也采用了Dijkstra算法,并进行了堆优化,使用了PriorityQueue这一个java自带的数据结构。
3.代码实现出现的性能问题和修复情况
本次代码没有出现性能问题,因为粗心导致了一个输出错误,希望加强中测强度,测出这一个错误(bushi)。
4.Network拓展
题目要求
假设出现了几种不同的Person
-
Advertiser:持续向外发送产品广告
-
Producer:产品生产商,通过Advertiser来销售产品
-
Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息
-
Person:吃瓜群众,不发广告,不买东西,不卖东西
如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等 请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格(借鉴所总结的JML规格模式)
Advertiser、Producer、Customer继承Person类,Advertiser与Producer之间关联,之后需要增设发送广告,购买,生产产品,设置广告,查询销售额,查询销售路径等方法。
选择发送广告
/*@ public normal_behavior @ requires containsMessage(id) && @ ((AdvertiseMessage)getMessage(id)).getAdvertiser().getId() == advertisementId && @ getMessage(id).getType() == 0 && @ getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()) && @ getMessage(id).getPerson1() != getMessage(id).getPerson2() && @ getMessage(id).getPerson1 instanceof Advertiser && @ getMessage(id).getPerson1 instanceof Customer; @ assignable messages; @ assignable getMessage(id).getPerson1().socialValue; @ assignable getMessage(id).getPerson2().messages, getMessage(id).getPerson2().socialValue; @ 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 \old(getMessage(id)).getPerson1().getSocialValue() == @ \old(getMessage(id).getPerson1().getSocialValue()) + \old(getMessage(id)).getSocialValue() && @ \old(getMessage(id)).getPerson2().getSocialValue() == @ \old(getMessage(id).getPerson2().getSocialValue()) + \old(getMessage(id)).getSocialValue(); @ 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; @ also @ public normal_behavior @ requires containsMessage(id) && getMessage(id).getType() == 1 && @ getMessage(id).getGroup().hasPerson(getMessage(id).getPerson1()); @ assignable people[*].socialValue, 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 Person p; \old(getMessage(id)).getGroup().hasPerson(p); p.getSocialValue() == @ \old(p.getSocialValue()) + \old(getMessage(id)).getSocialValue()); @ ensures (\forall int i; 0 <= i && i < people.length && !\old(getMessage(id)).getGroup().hasPerson(people[i]); @ \old(people[i].getSocialValue()) == people[i].getSocialValue()); @ also @ public exceptional_behavior @ signals (MessageIdNotFoundException e) !containsMessage(id) || ((AdvertiseMessage)getMessage(id)).getAdvertiser().getId() != advertisementId; @ signals (RelationNotFoundException e) containsMessage(id) && getMessage(id).getType() == 0 && @ !(getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2())); @ signals (PersonIdNotFoundException e) containsMessage(id) && getMessage(id).getType() == 1 && @ !(getMessage(id).getGroup().hasPerson(getMessage(id).getPerson1())); @ signals (CanNotSendException e) !getMessage(id).getPerson1 instanceof Advertiser; @ signals (NoUseException e) !getMessage(id).getPerson1 instanceof Customer; */ public void sendAdvertisement(int id, int advertisementId) throws MessageIdNotFoundException, RelationNotFoundException, PersonIdNotFoundException, NoUseException, CanNotSendException;
购买
/*@ public normal_behavoir @ requires advertisers.contains(advertiserId) && consumers.contains(customerId); @ requires message instanceof BuyMessage @ assignable getAdvertiser(advertiserId).getProducer(((BuyMessage)message).getProductId()).messages, salesValue[((BuyMessage)message).getProductId()]; @ @ salesValue[((BuyMessage)message).getProductId()] = \old(salesValue[((BuyMessage)message).getProductId()]) + getProduct(((BuyMessage)message).getProductId()).getPrice() * ((BuyMessage)message).getNum; @ ensures (\forall int i; 0 <= i && i < \old(getAdvertiser(advertiserId).getProducer(((BuyMessage)message).getProductId()).getMessages().size()); @ getAdvertiser(advertiserId).getProducer(((BuyMessage)message).getProductId()).getMessages().get(i+1) == \old(getAdvertiser(advertiserId).getProducer(((BuyMessage)message).getProductId()).getMessages().get(i))); @ ensures getAdvertiser(advertiserId).getProducer(((BuyMessage)message).getProductId()).getMessages().get(0).equals(message); @ ensures getAdvertiser(advertiserId).getProducer(((BuyMessage)message).getProductId()).getMessages().size() == \old(getAdvertiser(advertiserId).getProducer(((BuyMessage)message).getProductId()).getMessages().size()) + 1; @*/ public void purchase(Message message, int customerId, int advertiserId, int productId, int num);
设置广告
/* @ public normal_behavior @ requires message instanceof AdvertiseMessage; @ assignable messages; @ ensures messages.length == \old(messages.length) + 1 && @ (\exists int i; 0 <= i && i < messages.length; messages[i].equals(\old(message))) && @ (\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])))); */ public void addAdvertisement(Message message);
5.学习体会
感觉契约式编程在保证编程效果上的威力是巨大的,有了作用范围和作用效果的约束,一个方法的编写变得非常精确。在需要精确编程的时候可以多多使用。
而且感觉大多数情况下契约式编程还是挺好用的,编写代码时理解障碍比较小。但是也有例外,感觉这个在设计复杂算法场景的时候就比较反人类了,比如在涉及最小生成树算法的时候,相当难以明白,明白了对于写代码也没有太大作用。