面向对象设计与构造_第三单元总结

杨馨悦-22182610 2024-05-19 17:42:05

目录

  • 测试过程理解
  • 各类型测试理解
  • 数据构造策略
  • 架构设计与图模型构建
  • HW9
  • HW10
  • HW11
  • 性能问题及修复
  • HW9
  • HW10
  • HW11
  • 规格与实现分离的理解
  • Junit测试设计
  • 学习体会

测试过程理解

  1. 黑箱测试

    黑箱测试主要关注软件功能是否能按照需求规格说明正确执行,测试者无需了解程序内部结构或逻辑。主要测试输入输出,验证功能和系统行为是否符合预期。

  2. 白箱测试

    白箱测试也称为结构测试,测试者需了解程序内部逻辑结构,通过测试内部代码逻辑的路径,确保每个逻辑路径都被测试到。可以测试到代码的内部结构,有助于发现隐蔽的代码缺陷。

各类型测试理解

  1. 单元测试

    • 针对软件中的最小可测试单元(通常是函数或方法)进行检查和验证。
    • 通常由开发者编写,用来确保该单元能正常运行,符合设计。
  2. 功能测试

    • 测试系统的功能是否按照需求规格书执行,属于黑箱测试的范畴。
  3. 集成测试

    • 在单元测试基础上,将多个单元组合在一起,测试它们的集成是否能正确工作。
    • 目的是发现与接口和模块间交互相关的问题。
  4. 压力测试

    • 主要用来测试系统在超负荷运行和限制条件下的稳定性和可靠性。
    • 通常模拟高负载情况下系统的响应。
  5. 回归测试

    • 每当进行了代码修改(包括但不限于修复bug、添加新功能等)后,重新测试以确保修改没有引发新的错误。

数据构造策略

  • 构造有效数据:符合规格要求的正常输入。
  • 构造边界数据:围绕输入输出边界条件构造数据。
  • 构造无效数据:故意构造非法的输入数据,确保系统能正确处理。

架构设计与图模型构建

HW9

整体的架构和JML中的书写相同,需要特别注意的是isCircle,queryBlockSum,queryTripleSum这三个函数的实现.

queryBlockSum 和 queryTripleSum 都用的是动态维护的方法来计算blockSum,tripleSum的值。通过在addPerson,addRelation,modifyRelation时及时更新blockSum,tripleSum的值。

对于isCircle,我构建了并查集。并查集通过路径压缩优化查找效率,确保快速响应查询请求。

我采用了深度优先搜索(DFS)来辅助并查集的操作,在removeBlockSum方法中使用。

  • 当需要删除某个关系时,我会通过DFS来检查这个操作是否导致原有的社交群体分裂成多个较小的群体。如果删除的关系导致两个人不再直接连接,我会使用DFS遍历其中一个人的所有连接,看是否仍然可以通过其他路径达到另一个人。
  • 在DFS过程中,更新访问过的节点,确保每个节点只被访问一次,这有助于我判断是否还存在其他路径连接这两个人。如果遍历结束后发现两人不再连通,我会更新 blockCount ,反映新的群体数量。

我使用广度优先搜索算法(BFS)在 queryShortestPath 方法中找到两个人物之间的最短路径。

HW10

本次作业迭代中,主要增加了MyTag类,我使用大顶堆来维护了bestAcquaintanceHeap,在调用bestAcquaintance方法时,直接从堆顶取出,效率是 $O(1)$ .

public MyPerson(int id, String name, int age) {
    this.bestAcquaintanceHeap = new PriorityQueue<>(getAcquaintanceComparator());
    ...
}

public Comparator<Person> getAcquaintanceComparator() {
    return (p1, p2) -> {
        int value1 = queryValue(p1);
        int value2 = queryValue(p2);
        if (value1 != value2) {
            return Integer.compare(value2, value1);
        } else {
            return Integer.compare(p1.getId(), p2.getId());
        }
    };
}
HW11

在本次作业迭代中,主要增加了几个Message类,没有什么复杂度比较高的方法,我也没有做进一步的优化,直接根据JML写的。

性能问题及修复

HW9

本次作业,我一开始没有采用并查集,只是用Hash Map存了图,用DFS遍历的,时间复杂度比较高,尤其是多次调用 queryBlockSum 和 queryTripleSum 时,会导致TLE。

解决方法是按上面架构设计与图模型构建-HW9的方法来优化算法。

HW10

本次作业中,我的queryTagValueSum方法处理不到位,我没有考虑到在调用M有Tag类中的getValueSum时,时间复杂度是 $O(N^2)$ ,导致了TLE。

解决方法是在添加或删除标签内的成员、添加或删除成员间的关系,以及修改现有关系的值时,动态的维护MyTag类中的valueSum的值。动态维护时可以只扫两个人共同邻居的tag里是否有这两人,简化方法。

Set<Integer> neighbors1 = person1.getAcquaintance().keySet();
Set<Integer> neighbors2 = person2.getAcquaintance().keySet();
Set<Integer> commonNeighbors = new HashSet<>(neighbors1);
commonNeighbors.retainAll(neighbors2);
for (Integer neighborId : commonNeighbors) {
    MyPerson neighbor = (MyPerson) getPerson(neighborId);
    for (Tag tag : neighbor.getTags().values()) {
        ((MyTag) tag).updateTagValueSum();
    }
}
HW11

本次作业中,我由于JML读的不细致,没有读到/@ public invariant socialValue == money * 5;,所以我没有给MyRedEnvelopeMessage,MyNoticeMessage,MyEmojiMessage中的socialValue赋值,导致了较为严重的bug。Bug修复也比较简单,加上一句赋值即可。

规格与实现分离的理解

规格描述“做什么”,实现描述“怎么做”。规格应清晰、完整,又不能太过细节 容易局限住实现的方式,实现应尽量独立,便于修改和维护。

Junit测试设计

根据JML编写Junit测试,注意先检验是否符合规格的数据要求,拷贝一份network。比对修改的network和旧的network,更改的部分是否符合规格要求,不能更改的部分是否没有更改。

修改的network要能满足修改后的各项要求,且需要用一个正确的方法进行比对。

学习体会

本单元的任务其实不是非常困难,起初难点是JML的理解,随着对JML的理解逐渐深入,根据JML写出符合规格的代码实现也不再困难。容易出错的地方变成了算法是否高效,以及JML的阅读是否足够细致。由于很多情况下,需要多次调用计算结果的类,所以这类方法要尽量保证$O(n)$的复杂度,否则很容易造成超时。

...全文
154 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧