面向对象设计与构造第四单元博客作业

第四单元总结

第一次作业架构设计

类图

架构设计分析

本单元作业的要求和第三单元很相似,都是通过一系列输入构造出一个图结构,以及各种查找型指令查看图中各种元素的状态。因此,本单元的架构设计和第三单元非常相似,都是采用层层包含的关系,如代表UmlClassMyClass包含了代表UmlOperationMyOperationMyOperation里包含了UmlParameter。不过不同于第三单元,本单元作业大部分的元素其从属关系都较为唯一,不像第三单元里的MyPerson可以属于任意个MyGroup,同时还属于MyNetwork。因此,在本单元的架构设计中,对各个元素的访问域与包含关系也有更严格的设置。例如在对外的接口MyImplementation中,只包含了所构筑类图中所有的类myClasses,如果要对某个特定类的方法MyOperation进行操作,MyImplementation类只会找到这个类的实例化对象myClass,然后调用myClass里对应的方法,找到此方法的实例化对象myOperation后进行具体操作,而不能在MyImplementation中直接找到实例化对象myOperation。虽然从函数调用关系来看这样的调用复杂度高了,但各个类之间的层级结构更加清晰,且每个类的代码量也有所均摊,不容易出现一个类实现功能过多的情况。

第一次作业要求构成Uml类图。从层次上,很容易构建出class-(interface, attribute, operation)、(operation,interface)-parameter的树形结构。对于叶子节点,因为没有子一级结构,所以不需要存储额外的信息,只用官方包的Uml*来表示即可。而对于非叶子节点,需要记录子一级信息以及处理这些信息的额外函数,因此需要构建对应的My*类。此外,对于所有的构建操作,统一整合在一个工厂类ElementProcesser中实现。

第二次作业架构设计

类图

顺序图:

状态图:

工厂类:

架构设计分析

基本延续了第一次作业的设计思路。因为类图、顺序图和状态图三者都是彼此独立的,因此完全不需要修改第一次的结构,直接构造第二次作业需要的顺序图与状态图即可。二者的构造思路也和第一次完全一致。

考虑到三种图在构造的时候也不会产生交集,因此将第一次作业中类图构造的全部实现放到了ClassProcesser类中,并在同级新建了CollaborationProcesser类和StateProcesser类用于顺序图与状态图的构建。原来的ElementProcesser类则是变成了分发构造指令的类。通过判断指令类型决定将指令分配给哪个类去构造。

第三次作业架构设计

第三次作业只需要在第二次的基础上新增9个函数判断之前结构的合法性。因此就架构而言基本不需要进行修改,也基本没有因为函数而要新增的结构。依托于第二次的结构即可,类图与第二次基本相同。

学期总结

设计思维与OO理解演进

架构设计也算是OO课的重中之重了。虽然没有系统的花几节课的时间一个个设计模式的去讲,但整体回顾下来,每单元基本都在让我们切身体会各种的设计思路。

第一单元

第一单元主要是在使用工厂模式,通过递归下降法来在解析字符串的过程中构建出表达式树。也是第一次开始体会迭代开发的思想,新增作业时能发现如果当初在这里留一手,预备上可能会新增的功能,未来实现起来会方便很多。在第四次作业分析代码的时候,发现自己部分代码的耦合度太高了,有的复杂功能用一个函数50-60行去实现,导致代码可读性太差(也间接导致了一个bug的出现)。

第二单元

主要涉及了多线程可能使用到的各种设计思想,如单例模式、生产者-消费者模式、流水线模型等,个人感觉从各方面来说都是四次作业的巅峰。其中,我主要使用了生产者-消费者模型,针对性的设计不同地方共享托盘内需要存储的数据,以及访问临界区时尽量减少需要执行的指令,尽可能保证访问临界区后只执行存取操作,其他操作能不在临界区执行就不在临界区执行。最后一次作业中,借鉴了流水线模型标记mark的思路,对切割好的路径分段执行。此外,相比于第一次作业,代码实现上也有了诸多改进。因为初期架构提前留出了余量,后面迭代开发的时候也没有出现大量冗余的代码。一个函数也尽量拆成多个简单函数来实现,比如电梯开门时,将开门检查与开门操作分离成两个函数,避免出现过多的参数、变量调用。

第三单元

整体架构几乎不需要设计,主要在实现各个接口函数的功能。比较值得一提的是几个核心算法的实现。有些人在接口类MyNetwork中实现了算法所需的并查集。最后到第三次作业的时候发现代码行数超了。这方面比较好的设计思路应该是专门有一个并查集类作为数据结构类来存储并维护所需的数据结构,有点类似于ArrayList或是HashMap这样的封装好的数据结构。

第四单元

设计架构上基本参考了第三单元的官方架构。只需要按照OO的基本思想对代表Uml各个元素的My*类做好封装即可。

测试理解与实践的演进

第一单元

基本完全靠自己写的数据生成器,部分继承了上学期CO构造数据的思路,有常量池啥的。最后从强度来看随机性是有了,但对于各种比较偏的特殊数据没有覆盖到,有些地方也没意识到要构造下特殊数据来检验,算是第一单元两次错强测的罪魁祸首了。测试的时候用的python的sympy库,虽然输出结果不唯一,但sympy基本能满足比较的需求。虽然当时已经和别的同学拉了个群组成小组了,但还只局限于讨论实现思路以及各种可以卷死自己优化的方法,测试几乎是我单方面输出,因此有很多不足之处需要改进。

第二单元

第一单元错过两个强测点后痛定思痛,开始合作开发评测机了。本次的测试思路大致分为两部分。其一是数据的构造。在这一单元中,没有像第一单元那样有过多的特殊数据需求,主要思路是通过大量反复的测试寻找可能的多线程问题,因此适当限制后随机构造数据即可。其二是正确性的验证。因为输出结果不唯一,因此只能通过输出状态是否合法来判断。

第三单元

本单元采取了正确性+特殊数据两部分做数据构造。特殊数据的出现源自万恶的tle。实践表明,特殊数据是非常有用的,三次作业有两次都靠特殊数据成功卡出了其他人的tle。验证上,因为输出结果唯一确定,所以首次采取了同学间对拍的方法。值得庆幸大家的正确性都没有出问题。

第四单元

除了没有再构建特殊数据,别的基本和第三单元一样。也是因为快进考期了,各种大作业也多了起来,实在没有太多时间放到OO上了。(回家变懒了

课程收获

首先是面向对象的思想。虽然上学期JAVA课在上课以及完成大作业的时候已经在试着学习并使用这种思想了,但不少概念在OO课里还是得到了进一步理解。现在再回去看自己去年的JAVA大作业,能明显发现很多地方都有缺陷。比如封装问题,应该在类内部处理完直接返回处理后的结果,但却强行获取原数据后在其他类做处理。以及当时傻傻的为类里的所有属性都一股脑的设置了getset方法,而不管这些数据是否应该被外界访问&是否需要被外界访问。

其次是架构设计。第一单元的时候就因为架构设计的并不好导致进行过重构。这也让我意识到了架构的重要性。后面的作业基本都是第一天晚上发布后,先想想架构怎么设计比较好,和同学讨论下,再开始动手写。

还有就是课内各种其他重要知识点,尤其是前两单元。第一单元递归下降法,听说对下学期编译挺有用。第二单元着重于多线程思想,对我OS理解有不少帮助。

最后是小组合作。本学期整体而言OO的体验还是可以的,只有第一单元的两次强测以及对应的互测分别错过一个点。性能上也还不错。这要感谢和我一起写对拍以及做测试的其他两位同学@赵良兵@王永瑶,要不然光是强测可能就还要再多错出几个点来,更不要说互测要烂成啥样了。

课程建议

实验课反馈

实验课的目的应该是类似于training,能够帮助进一步理解以及完成作业的。所以,希望每次实验结束后,最好能给个参考答案或者解释之类的。

第四单元指导书修订

不管是群里的活跃状态还是反馈贴长度,明显能感觉到四单元歧义产生的问题比前面几个单元多得多(可能是因为三四单元对输入输出有比较严的规范,而第三单元形式化语言又避免了这一问题)。建议针对群里和讨论贴里提出过的问题对指导书上的描述进行修改。

预习部分增加内容

从实际体验来讲,预习内容实在有点少。尤其是对于上学期上过JAVA课的人来说,预习阶段的两个练习基本没有什么难度,收获也很少,只有类图还算是比较新的东西。希望可以把第一单元或者第二单元涉及到的一些东西适量加入到预习中,比如递归下降法。这样也能稍微调整下前两个单元的难度。

posted @ 2022-06-23 22:48  alonelysnake  阅读(24)  评论(0编辑  收藏  举报