面向对象程序设计第四单元总结

面向对象程序设计第四单元总结

标题为了一以贯之这么起叭,虽然说是第四单元总结,也是对这一学期OO课程的总结和回顾。

PART 1 第四单元架构

1.1 作业内容

第四单元的作业围绕UML展开,前两次作业的内容主要通过对类图、状态图和流程图进行建模,并通过一些指令查询模型中一些元素的情况,从而检验模型的正确性。第三次作业的内容是在此模型的基础上,前置一些形式检查的方法,检验图中的元素是否满足一些条件,如不满足,则没有后续指令的查询,直接退出程序。

1.2 架构及代码实现

1.2.1 架构

前两次主要实现的是建模,第三次主要是合法性检验。元素之间为包含关系,因此每次作业需要弄清楚自顶向下的元素分别是什么,再进行代码的编写,下面是我三次作业的架构。

第13次作业

第13次作业主要是实现类图建模,只要搞清楚包含关系,实现起来并不复杂, 主要的难点是在写class实现的接口的时候,既要考虑类本身实现的接口,也要递归考虑父类实现的接口和递归考虑接口继承的接口,在这个方法中时间复杂度会比较高,建议采取缓存机制。

第13次作业架构

第14次作业

第14次作业相比第13次作业多了时序图和状态图的建模,相比于类图,这两种图包含的元素比较简单,没有时间复杂度很高的方法,按照要求实现即可。

第14次作业架构

第15次作业

第15次作业相比于第14次作业多了8个合法性检查,因此在架构图中也多了一些元素,值得注意的是UmlAttribute是类图和时序图都有可能有的元素,因此在建模的时候要判断到底应该将UmlAttribute分给哪个模块,以免后续合法性检验的时候出现问题。

还有一点需要注意的是这次作业可能出现一个接口继承另一个接口两次,因此在保存的时候不能只用HashSet保存,因为HashSet对于相同的元素只会保存一次,因此在第15次作业中,我选择用ArrayList保存继承的接口,另外,在dfs的时候注意退出条件,否则在R003的时候容易出现死循环。

第15次作业架构
1.2.2 UML图及代码实现

因为第二次作业的架构完全是在第一次的基础上扩充的,第三次作业的架构与第二次作业完全相同,因此只展示第三次作业的UML图,通过阅读规则,我发现UmlElement之间存在并列关系和从属关系两种关系,同时根据题目中指令要求的输出,将其中的一部分元素进行封装,封装成自己的类,并在类中保存未来可能需要查询、输出、检验的属性。

第四单元UML图

在实现方面,考虑到一个指令对应的答案是唯一的,大部分复杂度较高的都采取了缓存机制,具体为用将需要返回的容器作为类中的属性,并增加一个布尔型变量flag,来标记这个指令是否已经出现过,如果出现过,直接返回该属性,否则,进行一系列的相关运算后返回,并令flag = true;。具体实现为假设是一个HashMap<String, MyClass> classes;,然后在对应方法中用以下的方法实现:

public void getClasses() {
	if(!flag) {
        //do sth to get classes
        flag = true;
    }
    return classes;
}

补充缓冲机制的另一种方法,最近闲的无聊翻了翻学长们的博客,发现有一个学长是这么写缓冲机制的:首先在构造函数中没有初始化这个属性,假设是一个HashMap<String, MyClass> classes;,然后在对应方法中用以下的方法实现:

public void getClasses() {
	if(classes == null) {
        classes = new HashMap<>();
        //do sth to get classes
    }
    return classes;
}

这种方法就可以避免多一个布尔型变量进行判断了,减少了程序的冗余,且功能完全相同。我一开始也想这么做来着,但是我想到的方法是判断它的size是不是0,这样就会当真的size为0的时候出现错误(最后结果没问题,但是逻辑上是有问题的)。

PART 2 课程总结

2.1 架构设计演进

Unit1

第一单元为表达式求导,在完成这次作业的时候其实我自己还没有想清楚架构就开始写代码了,所以会有很多架构中的冗余,两个类实现了相似的功能,比如ConstExpression和PowerExpression这两个类应该都是多余的,TermKey这个类也没有发挥出我一开始想达到的效果。不过在这次作业中,我学会了自顶向下进行分析(本次作业是对字符串进行分析),该方法也用在了第四单元的架构设计中。这是除了pre外第一次完成面向对象的一个小项目,也是我第一次完成超过1000行代码的编写,感觉总体上对自己这次作业还是比较满意的。

第一单元UML图
Unit2

第二单元是多线程电梯,如果说第一单元难点是架构的话,第二单元的难点首先是学习多线程的知识点以及代码实现,如何保证线程安全,还有如何检验自己输出的正确性,如何定位代码的问题。在架构方面相比于第一次作业已经清楚了很多,每个类都能够各司其职,并且能够很好的利用抽象实现具体,如用一个电梯类实现不同型号的电梯。

第二单元UML图
Unit3

第三单元感觉没有什么自己的架构设计,主要就是通过阅读JML代码实现功能,有很多同学一开始阅读JML规格后还以为必须用数组实现,导致第三单元的第一次作业性能爆炸,这一单元的难点是如何降低时间复杂度,考察了一些数据结构和算法的知识,如并查集,堆优化的迪杰斯特拉算法等。本次作业中掌握了JML规格的阅读,和一些简单JML规格的撰写(当然想写的一点毛病没有还是挺难的)。

第三单元UML图
Unit4

这次作业中架构的设计很关键,我采取的是将模型拆成三个子模型,自顶向下分别完成相应的功能,一方面实现了低耦合,另一方面也让我这个写代码巨长的人防止了某个类超过了500行的(checkstyle爆炸)。具体的架构在上一个小节中已经说的较为详尽,再这里就不赘述啦。

第四单元UML图

2.2 测试理解

BEFORE CODING

面向对象与面向过程的一个最大的区别就是,面向对象的代码编写不具有操作的连续性。以把大象放在冰箱里这个说烂了的事件为例,面向过程可以看作是打开冰箱,把大象放在冰箱里,关上冰箱三个事件,依次完成。而面向对象的过程则是:先写一个大象类,有进冰箱这个方法,再写一个冰箱类,有开、关两个方法,再写一个主类,主类中内容如下。

public class Main {
    public static void main(String[] args) throws Exception {
        Bridge bridge = new Bridge();
        Elephant elephant = new Elephant();
        bridge.open();
        elephant.goInBidge();
        bridge.close();
    }
}

上面说这些是想说明什么呢···可能很多人觉得面向对象很麻烦,对于比较简单的事情来说的确是这样的。但是如果功能变得复杂的时候,面向过程的方法无论是编写还是测试都较为困难,因此面向对象主要适用于较为复杂、实例较多的情况,而往往代码量也比较大。如果说面向过程的题我们可以边看题边写代码,那么面向对象最重要的过程则是写代码之前的架构构思。

以第一单元作业为例,相信很多同学都经历了两次代码的重写,几乎每两次作业之间都没有复用上一次的代码。出现这个原因的问题有很多,首先是一部分人带着面向过程的思维编写代码,还有一部分人虽然是面向对象的方式,但是由于第一单元作业的第一次作业有很多种架构方式,且后面的作业并没有提前公布,因此他们所采取的方式恰好在后面两次作业不能复用(这大概不能怪自己)。

架构的设计主要在写代码之前进行,当然,在编写代码的过程中其实也有可能会对之前的架构有推翻或者微调,不要明明知道自己的架构有问题还要一条路走到黑,适时的放弃可能会提高你的效率。

总之,架构的重要性,经历过的都懂,所以面向对象的代码,一定要三思而后编写。

CODING

编写代码的过程中,一定要进行单元测试!!!有一次作业直接写爽了一晚上写了1000多行,几十个方法,写代码一时爽,debug火葬场。单元测试的优点就是将程序测试拆分到每一个方法,检验每一个方法的正确性,保证每一个方法都能实现你想要的功能,那么拼到一起大概率也不会出什么问题。写到这里,突然想到在朋友圈里看到一位旁友发的图,一座摇摇欲坠的高楼,只要不碰它,还算是一座楼,但是碰一下就很危险了,这大概就是形容没有做单元测试,但是最后的结果暂时正确的人叭,这种状态感觉不是很好。在写代码的过程中,也要自己记录下可能出现哪些边界数据,以便后续的测试。

AFTER CODING

大一的时候被评测机惯坏了,同时当时只要通过测评机的评测就算任务完成了,因此几乎没有过自己构造数据检验正确性。所以课程中我收获的第一个测试方法(也不算收获叭,就是被软性强迫去做)就是自己手动构造一些简单的数据和边界数据。前者是为了检验自己程序大致的合理性和正确性,后者是为了防止一些边缘情况没有考虑,导致强测or互测凉凉的情况,后面发现其实这也不太够。此外,还要要学会一些构造数据的方法,还有自动检验正确性的程序。如何保证自动检验正确性的程序不写bug是一门学问,感觉还是蛮难的。另外,正确性唯一的作业可以采用多个同学对拍的方法检验正确性,该方法成本较小,难度较低,适用于后两个单元的作业。

2.3 给课程(组)的一点点建议

  • 希望实验课能够有答案反馈,在实验结束后也可以查看内容,方便复盘,并且总结自己哪里做错了,这样才能避免以后再次犯错。
  • 感觉虽然有pre的作业,第一单元还是不太适合作为面向对象程序入门的第一次作业,并且很多同学对正则表达式仍然不是很了解,希望能改一下,比如把第一单元的顺序调后,或者是直接提示大家不用正则表达式(因为后两次作业大正则貌似会爆栈)。
  • 是不是可以让每个同学在互测的时候看到自己hack到谁了,课程组把被hack次数设置成"?"的目的应该是防止某些人成为靶子,那只让自己看到自己hack的人是不是比较合理。类似于TLE还有多线程的东西,有的时候都不知道自己是不是hack到自己的目标了,(hack次数过多还有惩罚)。

2.4 课程收获

凡是过往 皆为序章

感谢大家(这里就不点名啦)陪孩子,一起讨论题目的思路,讨论or吐槽一些模棱两可的表述,一起对拍,一起深夜coding(指地理位置的一起)一起debug,一起赶ddl(我记得我以前不是ddl选手啊(#`O′))。大家真的很优秀,能结识你们真的很好。也很开心自己能够尽自己的绵薄之力帮助到一些同学。感谢用心帮助同学们的每一位老师和助教,也希望大家少一些阴阳怪气,多一些善良和诚恳。希望我身边的每一位未来的路都能越走越顺利,成为更好的自己。

还记得一次电梯作业,我出去dating,拜托某同学帮我测bug,结果他真的测出来了一个bug,我自以为改好了之后没有做回归测试直接交上去了,导致morning模式存在ctle的情况,强测爆了一个点,互测也被hack了一次(唯一挂的点啊(#`O′)),之后修复环节交了被某同学找到bug的版本就所有点都过了(老非洲人gxy)。

对一个喜欢的事情,多少也会带一些遗憾吧。

拜拜了OO,来日方长。

posted on 2021-06-18 21:36  gxy0615  阅读(301)  评论(0)    收藏  举报

导航

作者:玖梦
出处:http://www.cnblogs.com/ninedream/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。