BUAA_OO_Unit4阶段总结暨OO课程总结

OO_Unit4阶段总结暨OO课程总结

前言

四个月的OO课程(四个月的折磨)终于迎来了尾声,在这侧重分明但又相互联系的四个单元中,我在同学以及助教团队的帮助下克服了一个又一个困难,收获颇丰。

第四单元的正向建模与开发

先上类图

在这里插入图片描述

有一说一,这是我第一次在单元总结贴上自己画的类图,而不是照抄idea生成的类图,有点感动

本单元作业以现实中的图书馆管理系统为背景,在其中融入了“借书”“预约书”“捐赠书”“信誉分”等操作。

我将题目中的“学生”“借还处”“书架”“预约台”“图书漂流角”等类抽象成了BookContainer这个接口,在其中定义了几个共性的方法,如下所示

public interface BookContainer {
    
    int queryBook(LibraryBookId libraryBookId);

    void removeBook(LibraryBookId libraryBookId);

    void addBook(LibraryBookId libraryBookId);

}

然后我在使这些类实现这个接口。由于各个类的运行逻辑并不完全相同,因此各个类的接口实现也大相径庭。

例如在BookShelf类中,需要对初始图书类型以及数目进行初始化,因此需要init()方法;在BookShelf类中,存储书的数据类型是一个“ID对数目”的HashMap,而在Student类中,存储书的数据类型是一个"ID对日期"的HashMap,因此addBook的实现也有所不同

其中BookShelf,AppointmnetOffice,BookDriftCorner,BorrowAndReturnOffice采用了单例模式,并提供了静态变量方便外部类访问,如下

// 以BookShelf为例
public static final BookShelf BOOKSHELF = new BookShelf();

private BookShelf() {

}

这些采取了单例模式的类被组装到Library类中,并在Library类中统一进行访问和控制。Library主体代码如下

public void run() {
        init();
        while (true) {
            LibraryCommand command = LibrarySystem.SCANNER.nextCommand();
            if (command == null) {
                break;
            }
            LocalDate date = command.getDate();
            if (command instanceof LibraryOpenCmd) {
                open(date);
            } else if (command instanceof LibraryCloseCmd) {
                close(date);
            } else {
                if (command instanceof LibraryQcsCmd) {
                    queryBook(command);
                    continue;
                }
                LibraryReqCmd req = (LibraryReqCmd) command;
                LibraryRequest.Type type = req.getType();
                if (type == LibraryRequest.Type.QUERIED) {
                    queryBook(command);
                } else if (type == LibraryRequest.Type.BORROWED) {
                    borrowBook(command);
                } else if (type == LibraryRequest.Type.RETURNED) {
                    returnBook(command);
                } else if (type == LibraryRequest.Type.ORDERED) {
                    orderNewBook(command);
                } else if (type == LibraryRequest.Type.PICKED) {
                    pickBook(command);
                } else if (type == LibraryRequest.Type.RENEWED) {
                    renewBook(command);
                } else if (type == LibraryRequest.Type.DONATED) {
                    donateBook(command);
                }
            }
        }
    }

这样的设计层次分明,可拓展性强,为我的编程过程提供了莫大的便利。

代码设计和UML模型设计

说实话,在最开始做本单元作业时,我的的确确想像课程组推荐的那样,先画好比较完备的UML类图后再动手码代码。然而,就当我花了整整一个晚上画好UML类图后,却发现很多代码的实现难以和预先画好的类图相匹配,而且课程组提供的官方包过于强大,使得我在类图上的许多内容变得不必要。如果坚持先画UML类图再码代码,那么为了适配代码的变化需要频繁地回过头来修改类图,效率大大降低。

所以最后我屈服了,我开始写码代码再画图,一般是花一个晚上码代码,花一个晚上画图。

由于是先码代码再画图,相当于先有箭后有靶子,因此代码设计和UML模型设计的追踪关系也就无从谈起了

不过由于我在码代码前就已经基本规划好了大致的架构,码代码和画UML图时具有思维上的连贯性,因此事实上代码和UML图的一致性保持地比较好。

状态图

类图在上文已经提供并分析过了,以下是状态图,画的比较丑,请见谅

在这里插入图片描述

本状态图追踪的是“书”的状态,即书所在的位置

个人认为“逻辑上状态图还是比较清晰的”,以ao到各个其它直接相连的状态为例

  1. 调用pickBook()方法后,书有可能被预约的学生取走;
  2. 调用open()方法后,书有可能在开馆的图书整理中被从书架移动到预约台,也有可能从预约台移动到书架;

但是相信你们也能够看出来,本状态图存在极大的漏洞,即“对于Trigger相同的方法,没有加guard条件加以区分”,其实我也想加上guard条件,但是课程组所给的guard条件的约束过于苛刻,要求guard条件的填写符合一定的文法,且guard条件中出现的所有变量必须是某个类的成员变量。尤其是第二个条件,若我想要满足第二个条件,则必须大规模修改我的整体架构,在其中加上一堆“原本并不必要”的代码。这也是我认为绘制状态图要求的不合理之处。在权衡之下,我决定牺牲状态图一定的可读性而换取更好的架构完整性。

顺序图

以下是顺序图

在这里插入图片描述

说实话,我觉得在一个单线程的程序中画顺序图挺奇怪的,而且事实上我并不认为这些类中传递了什么消息,顶多就是方法间的嵌套调用存在顺序关系。因此课程组的“绘制状态图”的要求一度让我感到为难。

但是好在课程组只要求对借书过程中的orderNewBook()getOrderBook()两个过程进行绘制,这两个过程还算结构清晰(课程组,你好善良),因此绘制起来难度并不大。

我以orderNewBook()过程为例,介绍顺序图的逻辑

  1. Library收到请求,调用orderNewBook()方法,“提醒”BookShelf
  2. BookShelf收到“提醒”,orderNewBook()方法调用结束;
  3. 在开馆整理中,调用AppointmentOfficeaddBook()方法,对应书籍移动到AppointmentOffice中;

四个单元中架构设计思维的演进

在第一个单元,也许是由于初次使用面向对象的思想处理比较大型的项目,因此架构设计并不成熟。例如我没有对具体的数字,变量,指数函数和表达式,项,因子进行进一步的抽象;我甚至还将所有与计算相关的方法全部放在Cal类中,造成代码臃肿。这都是不成熟的体现;

在第二单元,我开始有意识地进行架构设计,然而由于我“思维比较独特”,我并没有设计类似于“输入流”的类,然而将“添加输入”的任务下放到每一个电梯对象之中。这在第五次作业中给我带来了便利,但是在第七次作业中我因这种设计造成了大量死锁bug,而且由于复现困难,我不得不花费整个清明假期去debug。但总体而言,我在第二单元中形成了自认为比较成熟的设计思维

第三单元聚焦于规格化设计,并不存在什么设计架构思维,深究起来,也许将点集抽象成并查集算架构设计?就此略过。

第四单元架构比较成熟,也是我个人目前最为满意的架构设计。架构在上文已作说明,不再赘述。

四个单元中测试思维的演进

上完OO四个单元,我最大的感受之一便是**“评测机真的很重要”**,我个人也与gpf同学合作开发评测机,评测机项目已在github开源

项目地址:solor-wind/BUAA_OO_TEST: BUAA OO课程的评测机 (github.com)

麻烦点个star,谢谢喵~~ (๑ơ ₃ ơ)♥

在这个过程中,我们通过合作开发代码,让我积累了许多团队协作方面的经验,让我受益良多。

说会正题,你在写完代码后不会知道你的程序有多少Bug,因此大量的评测十分重要

在搭评测机的过程中,我们会刻意避免使用与java程序一样的思路(毕竟如果我java都写错了,难道python还能写个对的?),在第一单元中我们使用了sympy库进行正确性检验,在第二、四单元我们使用模拟进行正确性检验,在第三单元我们使用了XNetwork这个python中用于计算图论的库进行正确性检验。

至于数据生成,我们将“调整数据生成参数”这一过程下放给用户,用户可以调整config.json来改变测试的侧重点和强度,以下是第二单元的config.json示例

{
  "in_path": "input.exe",           // 官方数据投喂器路径
  "jar_path": "myJar.jar",          // jar路径

  "delete_temp_files": true,        // 是否删除临时文件,用于检验数据生成强度

  "set_clock": true,                // 是否定时
  "clock_time": 120,                // 定时时间

  "my_input" : false,               // 是否采用自定义的输入

  "max_thread_num": 20,             // 最大同时运行评测线程数目

  "test_num": 1000,                   // 测试次数
  "time_limit": 20,                 // 数据所给的时间范围

  "command_limit": 200,              // 指令条数
  "fault_tolerance": 0.01,
  "elevator_num": 6,                // 电梯个数
  "default_floor": 1,               // 默认初始楼层
  "min_floor": 1,                   // 最底层
  "max_floor": 11,                  // 最高层
  "move_time": 0.4,                 // 每层移动时间
  "open_time": 0.2,                 // 开门时间
  "close_time": 0.2,                // 关门时间
  "capacity": 6,                    // 电梯容量
  "reset_prob": 0.1,                // 生成reset指令的概率
  "DC_reset_prob": 0.3              // 在生成reset指令的前提下,生成DC_reset指令的概率
}

生成数据也是一门学问。在第一单元和第二单元中尚且可以随机生成,但第三单元和第四单元则必须“刻意”地进行数据生成。在第三单元中,我们采取了“将生成图的过程拆分,并随机再排序”的方式基本保证了生成数据的强度;在第四单元中我们则采取了“交互式”评测,依据用户程序返回的输出动态调整输入,也取得了不错的效果。

但是评测机并不是万能的,它无法覆盖一些极端的,边缘的数据。我在第二单元的互测中就因“评测机测试一万次未出现bug”而过于自信,被极端数据hack导致互测失分。因此,我认为,在使用评测机大量评测的前提下,手动捏造极端数据进行测试才是进行测试的正确方式。

OO课程收获

总体而言,我在OO课收获很多。

  • 在第一单元中,我掌握了面向对象的基本思维和程序的架构设计;
  • 在第二单元中,我基本掌握了多线程程序的特点以及编程方法,学会了“对抗”死锁的方法;
  • 在第三单元中,我掌握了规格化设计的方法,学会了“戴着镣铐跳舞”,并且使用Junit对程序进行测试;
  • 在第四单元中,我则学会了基本的UML图的绘制方法,懂得了保持程序架构和UML图的一致性;

每一次克服课程组布置的挑战,看到在强测中取得的好成绩时,我的心头总会涌起一股激动的暖流;而在课下同学们相互交流,彼此出谋划策攻克难关也让我感慨万分。
我想,这也是这门课的魅力所在。

  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值