OO Unit Four总结
Written by: 18373541-xiaohan209
本单元代码架构设计
第十三次作业
设计策略
这次的作业属于这一单元开头的部分,可以说是这一单元作业中代码量最多的了。这一单元要处理类图的所有元素,有方法、方法中的参数、属性、关联关系、类实现接口、接口和类各自的继承关系。并且本次需要实现的交互类当中,也是主要以类和接口来进行查询的,于是直接在交互界面下存储所有类和接口,并且能通过名字找到,还能知道是否重名。然后在类和接口下,用HashMap
存储方法属性等,另外就是继承,实现,关联的关系也需要在此存储起来,也就是属性方法和关系都是同一个层次的。另外值得一提的是存储关联关系并不是将对端类存储,而是将associationEnd
存储起来,这样可以保证两个类间有多个关联关系。最后一层在方法中存储参数。
在读入的时候需要遍历三次,由于输入并不保证顺序,所以第一遍主要在于读入并且让程序可以对应id找到元素(这里的元素指的是我自己封装的一个类),另外就是第一遍读入的时候如果是类或者接口,直接建立变量,方便后续的装入。其实这也对应上述的类和接口是第一层。之后第二遍是加载方法、属性、参数、关系等,这些基本上是可以归到类或接口的内部成员变量的,因此只需要一遍遍历,将其存储即可。第三遍是比较重要的,就是更新每一个类,找到所有的关联关系,属性,祖先等。本单元受JML单元启发,依旧采用了缓存的思想,将这些都存起来,有需要就查询即可,因此对于有一些函数需要知道这个类以及其上所有的祖先当中的信息,或者知道实现了哪些接口,但是这个接口其实是含有继承关系的,需要单独由下到上扫描,并添加进自己的内部成员进行缓存。由于这里不存在循环继承,所以直接进行更新的时候可以设置脏位,如果脏则更新,并更新他的祖先们,如果不脏直接返回,节省时间。
在查询的时候首先从交互类中得到类或者接口等,然后再调用类当中的方法完成后续操作,类可能还会调用更底层的属性类当中的方法等来进行层次化的交互。
原本这一单元想采用starUml的方式来画出本次作业的类图,但是元素实在较多,并且其中的属性和方法过于多,显得有些错综复杂。继承关系倒是比较简单,但是关联关系还是有一些的,包括一些依赖关系,导致第三次作业太难画出来了,还是选择了JAVA的自带的UML类图进行分析。并且最终UML图如下:

可以看到这次作业明显层次很分得清,有第一层一直到第四层,并且所有元素都用MyUmlElement
进行了抽象,很好地体现了封装性。首先本次作业没有了中间层,就是那种在两层中间生生突出来一层,并且本次可以看到箭头等都是比较规整的,没有绕开一大段然后关联到某一端的,尤其是最上面的继承关系,非常规整,再对比第一次作业的架构,就可以发现真的有天壤之别。
复杂度分析
同时代码的smell分析如下:


这里只展示了5行以上的方法,由于层次比较多,很多函数直接就是调用内部某个成员的方法,然后直接return
这个方法的返回值,在此不列出来。可以看出方法当中MyUmlInteraction
的构造方法占了很多行,感觉像是一个God类,但其实这里构造的时候就对所有UML
的元素进行了遍历,并且是三遍遍历,其中switch-case
语句占了很多行。这个方法算是一个分发方法,进行判断之后,直接调用需要的元素的方法,并不在构造方法内直接进行处理,这样更好体现层次性,奈何还是种类繁多,行数过于多了。并且由于上述原因,这个构造方法和其他方法的调用复杂度也比较大,因为这是一个统领方法。其他方法基本正常,都是在40行以下,没有太庞大的方法,复杂度也控制的比较好。
在对自己创建的各种类分析的时候,可以看出MyUMLInteraction
和SuperUmlClass
的行数比较多,这个是事先就会料想到的。因为交互类本身就有很多的方法,不可避免需要进行各种查询,并调用内部元素进行查询。尤其是异常的抛出,虽然代码较为相似,但是很难简化,每个函数抛异常的部分占6行,之后的调用可能占1-3行,这就导致代码量一下陡增,但是MyUmlInterantion
其实并没有变成万能类,而是有层次地递归查询。另外就是对于SuperUmlClass
这个类,存储的元素比较多,许多方法都是直接对某个成员变量进行查询。唯一比较复杂的就是在更新的时候,需要从子类一直到所有的祖先都进行更新,是一个递归深搜的过程,并且这里需要用到父类的元素加到子类里面,所以交互复杂度较高。
所以通过以上的分析可以得出MyUmlInteraction
明显要比其他类复杂,但是这是不可避免的,毕竟需要实现的函数就众多。但是这并不代表不能简化了,其实还可以对其中的一些函数进行封装,并且层次增多,这样每个函数都会变得简单,这个类也会减少一些复杂度,但是带来的就是又要有新的Uml
元素了。
bug分析
这一次作业强测获得了满分,没有测出bug。在作业完成前自己课下测试的时候出现了一些问题,主要分为两类。
第一是题目理解有误。比如关联的到底算不算父类,一个类如果实现一个接口,需不需要将接口的关联关系添加进来。本次作业的讨论区有非常暖心的上学期问题贴,强调了只算继承的,不算实现的,要不然这个题目会变得异常复杂。正是实现关系,分隔开来了类和接口之间的层次,可以分开来管理。
另外就是自己对于UML
图并不熟悉,StarUml
也没太常用,一开始并不知道两个类之间能够重复地建立好几次关联,导致一些样例一直过不去,后来找到了这个bug特地对每个关系亲手进行了实践,并在右侧元素栏里看各种元素的层次和是否能重复。
第十四次作业
设计策略
在上一次基础上,本次作业加入了statemachine
和collaboration
了。这两个类都有一个共同的特点,就是都用了一个画布,但是每个这样的machine
只会拥有一个画布,但是在这里我还是选择将画布当做一个层次存了起来。另外我将第一次作业的交互类当中的一些信息,比如找到UmlClass
等单独抽象为MyModel
类,在交互类构造的时候遇到类图元素就交给这个类来继续构建。与此平行的还有statemachine
和collaboration
,都变成一个单独的层次,表示彼此分隔开来,交互类在这些类存储好信息后,将他们的索引(就是根据id或者name找到对应的元素,以及是否重名)都拿出来当做自己的信息,并且在交互函数调用的时候可以用到。另外对与UmlStatemachine
和UmlInteraction
,需要在第一次当中建立,并且加到statemachine
和collaboration
当中。然后画布信息以及其他的信息在第二次遍历跟第一次作业一样加入即可。最后是statemachine特有的state的更新,需要找到后面的所有状态,这个就像找继承的所有祖先一样,只不过可能有循环继承的问题,所以需要进行标记,否则可能死循环。
于是整体UML图如下:

可以看出这个UML图一下子变得复杂了很多。但是层次还是比较清晰地。首先是第二层左侧的MyUmlModel
是第一次的作业的interaction
的功能的抽象出来的一个层次。在它的上方的九个类都是类图的元素。然后第二层中间的是MyCollaboration
,里面存储的是顺序图的所有元素,并且提供交互功能。它之上的五个类都是顺序图当中的元素。值得一提的是这个Attribute
其实是横跨了顺序图和类图的,所以这也就需要我们在大的MyUMLGeneralInteraction
当中存储所有的信息,要不然完全的割裂开,会发现有的attribute
找不到该加入到哪里,变成了孤儿。之后第二层右侧的MyMachine
是表示状态图的。它上面的6个元素是属于状态图中的元素,状态图相对独立比较好处理,完全可以与另外两个分离开来。如此一来,会发现整个类的结构甚至比求导的第三次作业还复杂,我一直认为求导第三次作业是最复杂的。但是可以看出来这个UML
图完全是有层次结构的,并且不会乱,较为统一,新添加东西也可以找到需要添加到的层次,比如在关系当中增加依赖,那直接放入类图当中即可,可拓展性很强。当然这也是得益于这一单元学习的就是UML
类图,本身就是具有层次的作业,比较好抽取。
复杂度分析
本次代码的smell分析如下:


这次代码的方法挑选了10行以上的代码,由于十行以下基本都是用来层次化调用的,没有太多的逻辑价值。可以看出本次没有像上次一样出现很长的方法,这主要是由于checkstyle
过不了所以修改的。在MyUMLGeneralInteraction
初始化的时候,直接将几次遍历分成了不同的函数,并且遍历当中某个分支需要调用某一种类的machine并且进入到下一层构造当中,这就是方法中这么多goto
开头的函数的由来。所以这一次明显比上一次在方法上改进得好一些了。
但是在类方面还是有所欠缺,比如MyUMLGeneralInteraction
直接飙到了427行,这个代码量checkstyle
都快报错了,也就是一个java文件不能超过500行。与此同时这个类的交互复杂度也很高。但是比较欣慰的是,在上一次作业的基础上,并没有给以前的代码增加太多负担,原本代码比较多的SuperUmlClass
并没有更沉重的负担,而是直接增加了很多的类来表示其他种类的machine
和其中的元素,这个是第一次在自己完成的代码中做到新增任务不修改以前的代码的原则,内心狂喜!
bug分析
本次在强侧中没有bug。但是线下测试的时候碰到了一些问题,比如状态图当中找后续状态没有做标记,直接死循环了,但这个比较容易发现。另外就是一开始没有把初始和最终状态当做普通的状态来处理,然后在状态数上就出现了问题,也比较好发现。
第十五次作业
设计策略
本次代码的UML图跟上次代码一样,只不过增加了交互的函数,以及一些内部的属性来看是否有重复的部分出现。在此不列出UML
图了。整体设计沿用上次框架,在此分享bug修复后的逻辑层次。
对R001,只需要交给MyModel
处理即可,对所有已经记录下来的来进行查找,然后交给每个类去查找内部指定的变量是否有重名的。这里需要注意的是不算父类的属性和关联点。
对R002,由于类和接口之间被实现分隔开来,所以这里只需要类和接口各自调用自己内部的函数去查找即可。由于时间较为宽限,所以查找方法是从这个类或者接口开始深搜,遇到重复的就直接返回真即可,如果没遇到就返回假,并回到上一层搜索。由于可以循环继承,所以对于之前第一二次作业的更新祖先,又都添加了访问标记,防止死循环。
对R003,由MyModel
交给类和接口分别处理。对每个类或者接口先建立一个HashSet
叫idSet
表示现在有的类或接口id,再一个HashSet
叫dupSet
表示现在重复的类或接口id,然后进行广度搜索,遇到祖先,就把他们的重复id集合先加入到dupSet
当中,然后将直接继承的类或接口的id拿出来,如果idSet
包含,就直接放到dupSet
当中,如果不包含,那就加入idSet
。最终看是否有重复的就可以了。
对R004,与R003差不多,只不过是需要在广度优先搜索的时候考虑父类并更新idSet
和dupSet
之后,再根据这个类实现的所有接口继续更新idSet
和dupSet
。
对R005,由于是对类图元素进行访问,所以还是交给MyModel
进行处理,一次遍历之后统计所有名字为空的,并返回即可。
对R006,依旧交给MyModel
来处理,同样遍历,只不过这次遍历的是所有接口,并交给接口当中的方法进行查找看是否有不是public
的。
对R007,交给MyMachine
处理,直接对所有状态进行遍历,找出是final state
的,并且看是否这个状态有紧邻的transition
。
对R008,交给MyMachine
处理,直接对所有状态进行遍历,找出是初始状态的,并且看是否有紧邻的多于一个的转移。
复杂度分析
代码的smell分析如下:


这一次迭代开发发现一二次作业虽然比以前的单元做的好了,但是还是不够完美,导致这一次作业要改一下前面的更新和搜索方式,不能直接深搜了,要添加一些标记代表访问过,这个标记都是在类或者接口这个元素类当中存储的。另外就是要存储额外的信息,自己直接继承和继承的所有的,自己的关联点和所有的关联点,以及是否本身就有重复的继承。
由于文件过了500行,所以直接将一些switch-case语句变成了if-else,另外优化了一些写法,这使得原来的方法变得更加简洁了,所以方法分析中行数也减少了许多,更加符合规范。但是在类的分析当中可以看到SuperUmlClass和SuperUmlInterface当中代码行数变成了200多,这一部分是由于MyUMLGeneralInteraction的一些方法继续下放到了这两个类,一部分是由于检查规则需要新建并调用到接口和类的内部方法。但是这次并没有新加别的类,直接通过层次化的调用可以完成检查的功能,总体设计良好,除了循环继承的问题(由于采用缓存,必须在查出继承之前就考虑到循环继承),其他的改动都不大。
bug分析
本次强测出现了一个bug,就是对于下图这样的菱形图,由于深搜没有做到很好的标记,导致可能会一直嵌套,但是其实对于每一个点,访问过一次已经可以提取足够的信息了,如果可以一直访问的话,像菱形图这样高度成环的结构,时间复杂度会变得很大。所以需要对其进行标记,但是标记怎样取消是难点,最后直接将深搜改为广搜,就不需要标记了。因为广搜只在一个类或者接口内进行调用,不会深入到每一层去递归调用。所以以后遇到比较容易有环的图,或者不是树的,还是用广度优先比较省事。

另外私底下还发现另一个bug,就是对于题目没有太理解导致的,R001当中的AssociationEnd不用考虑所有祖先的,但是我一开始写的时候算上所有祖先了。
四个单元架构设计及OO方法理解演进
第一单元
这一单元其实还是处于pre阶段,因为只在寒假当中通过题目自学了语法,并没有掌握核心的OO思想。所以设计架构就是有啥活接啥活,要处理正则,好那就来一个regex
类,接受输入。有常数,有幂函数,那就建立两个类来表示他们,说句实话这里起始跟数据结构的结构体的感觉差不多,内部的一些方法也只是为了输出,或者纯粹计算导数,也可以用面向过程的方法来写。所以这一阶段还在被动完成任务的架构当中。到了第三次作业,又一次重构之后才建立了一些层次,比如项是一个较高层次的,项当中包括因子,因子又有常数,函数,括号代表的整体,幂函数等。并且正则的处理也变成了层次化处理,就是先分离成每个项,然后项内部再分离出因子,因子内部再看是什么类型,在根据类型新建一个对象。最后求导过程是因子求导变成项,项求导变成表达式,每次求导就会变成上面的层次,最后将这些东西整合之后输出。
第二单元
首先建立一个电梯类,主要功能都交给电梯来处理,电梯是个Runnable
的类,自动寻找最近的有人的楼层,并且可以根据电梯内人的请求判断主需求并随时更新,然后还有承担上下人以及更新请求的操作。我没有设立单独的调度器,完全让电梯们自主竞争。只不过还需要一个加入人的需求的生产者,以及中间的缓冲区托盘。在这一单元当中感觉更多的学习的是同步,所以并没有像一些同学一样自己建立一个专门的调度类去调度,所以性能上并不是很优。但这个架构本身是没有问题的,是借用了生产者消费者模型,只不过消费者消费的方式较为复杂,需要分成几个步骤。这次的架构设计就要比第一单元更优,因为对整个项目进行了分析,甚至第一次就直接想到每个电梯是不同种类的,需要预留开关门时间信息以及载客量信息,但是没想到停靠层数信息。
第三单元
第三单元的结构设计其实并不是自己的设计,更多的是依托课程组的架构进行设计,显然我一开始对JML这一单元并不了解,以为有了规格整体都是固定的了,只需要按照规格来翻译就好了,结果就是只是单纯照搬了函数,并且结构也没什么变化,顶多是在第三次作业新建了一个存储边的信息的类,来实现优先队列。后来才发现JML其实只是形容了顶层的接口,只要你能对接好,里面可以分层次存储各种信息,没必要只有两三个类。但说实话,要实现社交网络的基础功能的话,课程组的结构已经逻辑很清晰了,在此我也学习了拓展功能的基础上不修改之前的方法需要保证之前的方法独立,不会对新增加的一些属性有影响。
第四单元
这一单元属于综合了上述三个单元,总结了自己不好的架构,学习了优秀的架构之后,进行了设计。首先对于课程组给的UmlElement
进行了封装,变成了MyUmlElement
,然后所有的类图状态图顺序图的元素都是继承自MyUmlElement
,并且根据UML
本身的层次,类和接口是底层,参数是最上层,来逐步分层设计。这样的好处就是如果题目要求查询什么都非常的快,需要类中的某个属性,直接先找类,然后交给类来处理,调用类当中的方法,直接遍历内部属性,最终再一层层返回给外部。这也使得代码效率提升了很多。
总结
感觉这几个单元下来,感觉层次化是OO架构设计的关键。第一单元本身不了解OO,再加上拓展的可能比较多,比如对数函数之类的,就会有点不知所措,不知道这些数据都有怎样的层次关系。但是到了UML
这一单元,本身就有一个功能很强大的StarUml
,这其实已经大致知道了我们需要存储的所有元素的功能,以及其中的逻辑关系,这就很好预想未来需要拓展什么功能,更好层次化设计。另外其实这几个单元过来,设计当中的封装性我也有所改进。比如在UML
这一单元我就将好多类内部的方法改成了private,然后只预留了一些查询接口给外部进行访问。而像一开始的求导单元,很多表达式等,都是直接将内部的函数或者常数项的信息拿出来,然后再数据处理,这其实就可能造成安全隐患,因为可以直接修改内部的信息。现在我也在想,假如,先学JML
和UML
,JML
课程组给了让方法彼此独立,拓展不修改前面的内容的项目,UML
让大家知道一个庞大的UML
元模型集合怎样有之间的层次,锻炼了层次架构设计。那么会不会第一第二单元学起来更加轻松一些呢?当然这不能排除时间因素,学OO学的多了自然顺手一些,可能第一次直接UML
这么庞大工程会吃不消,也不知道是好是坏。
四个单元测试理解与实践演进
第一单元
这一单元纯属手动测试,觉得其实没有必要用对拍机,因为要考虑性能等,所以有时候手动构造极端的样例,比如兔斯基表达式,或者括号套娃等数据,更能检测性能和有没有死循环等。于是全都是手动写数据,然后脑补求导结果,最后比对。显然这样是比较费时间的。
第二单元
多线程是比较玄学的,不好重现错误,所以这部分内容首先是对于一些数据的冲突形式化验证,分不同种类的冲突来考虑。当然自己的考虑还是有限,暴露出了很多问题,但是这部分并不好对拍,所以也没有写对拍机。总体还是根据平台的反馈结果来看自己哪里漏送了人,哪里门没有关上,还是没有系统化的验证形式。
第三单元
这一单元终于构造了自己的对拍机。因为涉及到图的各种信息的访问,大的数据才是检验程序正确性的最好手段。并且这部分输入输出信息很好统一,基本都是确定的结果,这也给对拍机提供了方便,只需要对比输出结果是不是一致即可。所以这单元用python
写了一些自动化测试内容。当然这一单元还介绍了一个重型debug方法JUnit
,这是搭配JML
有的测试方法。主要是对于某一个函数进行测试,前面构建好整体的环境之后,测试函数的输出并与断言的结果进行比对。这其实是第一单元测试的升级版,但是这显然对于一些极端数据的情况检验更加有针对性。并且每个极端数据可以分别检验不同的方法,不会某个方法是错误的,但是极端数据不会用到,所以检测不出来。
第四单元
到这里又开始普通的手动验证了,原因是StarUml
能够图形化地构建样例,并用jar
进行导出。所以这里也是采用了极端数据验证。并且本次交互接口中的方法也是彼此独立的,可以为了验证某个方法而针对性写测试用例。但即便这样,课程组的数据也给我上了一课,就是之前bug分析当中提到的菱形图,这样的图如果纯粹深搜不设置脏位的话,时间复杂度非常高,所以图还是广搜为妙。但是其他的情况测出来了一些bug,好多还是没理解题意的问题。这种测试方式主要是基于架构来的,如果架构没有做到方法之间分离,可能会修改方法内部的值,那么测试效果肯定不理想。
总结
OO的测试方法其实也是不断学习层次化的过程。从一开始的随便想一些表达式来求导,到最后的可以利用JUnit
或者单独构建某个方法的测试用例,这其中首先就需要知道我要测哪个方法。第一单元如果单测一个方法,我可能都说不上来前置和后置条件是什么,因为层次混杂,很乱。但之后由于层次的分离,就可以准确定位有问题的方法,并进行测试。所以从测试的角度来看,OO的实践还是一个不断抽象、提取的过程,如果不能有效建立一个高内聚低耦合的结构,那么测试都将变得很困难。
课程收获
在这门课程当中,我收获颇丰。第一,也是最重要的点,设计的思想从面向过程到了面向对象。不得不提到一件事,就是这学期我同时担任了大一的数据结构助教。这两门课程的学习内容,和训练方式比较相似,都是以某个具体的任务来写代码,然后进行评测,题目都比较具体。但是区别就是OO的作业有迭代开发的制度,我认为这个是提升个人能力掌握OO思想最有效的手段。
首先是封装性,在第一次作业或者寒假的准备作业当中,有些比较简单的题目我也是一个main
方法,然后顶多再建立一个类进行调用,这显然不利于拓展,完全是照搬面向过程,并没有根据需要的数据的层次来建立封装的对象。但是在第一单元过后,其实这种封装思想已经建立地比较好了,所以第二单元的电梯第一二次作业甚至都用的同一个架构,基本没怎么改过,可以做到只在某个对象内部多添加信息来解决。
另外就是可拓展性。第一单元三次作业,没有一次是在原有基础上添加有关的信息即可解决问题的,全都是从读入到处理再到输出重新构造了一遍。之后看了同学们的优秀代码以及老师的解答之后了解到了要建立一个抽象层次,并在这个抽象层次下具体分类,比如是普通的次方项,还是常数项,还是函数项。后面三个单元,我都会着重给后面的开发留出一定的空间。
面向对象的好处。首先是bug定位和分析,相比面向过程,面向对象的层次更加清晰,某个方法到底层去调用会有比较清晰的逻辑。就像有一个方法是需要将两个UML类元素建立关联关系,那么需要分别调用两个UML
元素的添加关联关系的方法,在这里就对告知程序需要添加关联关系,和具体某个类添加关联关系进行了独立,有点像物理设备和逻辑设备一样。面向过程就需要直接在得知添加关联关系的情况下根据id自己找到信息,并且添加关联点,很复杂,以至于并不知道在哪里输出调试信息,或者检测是否添加进关联点。但是面向对象当中我经常使用的一个调试方法就是在方法的前后打印进入方法、得到的参数和退出方法、返回结果的信息,这样就相当于起到了分层调试的作用,很容易定位bug在哪。另外面向对象还有好处就是所有对象都是模块化的,如果一个对象出现了问题,比如是个空指针,那么很好发现,有的时候甚至不影响其他功能,但是如果面向过程的话,第一很难知道哪里抛出了空指针,并且程序整体都会无法运行。
所以对面向对象的这种思想的体会在后面设计软件架构的时候都会很好地用到。
改进建议
- 写在第一条,实验部分建议能在之后给出一些提示,哪怕标答不给的话,也给一些可能出现的错误呗,就像中弱测样例一样,在测试之后可以部分给出答案,部分不给,或者一部分数据点公布出来,一部分不公布,要不然真的不知道自己对错感觉实验没什么意义。
- 在JML这一单元,就不要整JUnitNG了!!以及那个奇怪的OpenJml,简直就是折磨人,关键是JUnitNG跑出来测了很多null出来,但是其实这个函数传进来的参数已经在调用者那里保证了不为null。另外JUniNG对一些很简单的逻辑判断都很难体现正误,有的时候只是输入极端数据,看你程序崩没崩,没崩就认为是好的程序。
- 希望UML这一单元能够对一开始的类之间的关系做个更细致的对比,并且结合一些生活中常见的例子,感觉现在还是分不清依赖,聚合的用处。另外就是出租车的这个例子感觉有点不太好理解,如果可以希望换一个例子(当然这点纯属我个人感觉,当时看了好长时间才大致知道ppt中图画的是什么,感觉我跟这个出租车例子思想不契合)
线上学习OO体会
这一学期线上的学习总体来说感觉还是没有线下学习好。首先是交流方面,不好与老师和同学们沟通。其实在学校和老师交流也并没有那么多,最重要的是同学们比较优秀的思路只能在博客区看到了。
其实第一二单元这样的涉及到具体细节的单元,线上授课效果较好。就像求导单元,主要是联系正则表达式的使用,其实是一个比较具体的方法。以及对于多项式的层次化表达,也没有整体的框架,都是自己随意发挥,因为管理的数据结构比较单一,都属于多项式,可以都抽象成一个大的顶层类。
像第二单元其实也是比较具体的,到每一层,然后换成等,都是具体的动作,虽然要考虑到并发性,但是实现的过程也比较具体,相当于是甲方的需求已经到很细致的地步了。这样再继续完成项目的功能就比较简便。另外老师上课的时候讲这两单元也是介绍了相关的细节实现,以及一些比较好的层次架构。线上这种可以往回翻看的好处就显现出来了。另外老师的问卷也在一定程度上起到了温习作用。
但是三四单元是从一个整体的更高层次进行了架构,包括对一个类或者方法的规格设计,以及最后的UML解析器,实际上是很抽象的一个层次。这种项目上,理解就成了最大的一个困难。老实讲,UML这一单元后两次课基本上都是一知半解,听过老师讲课就过了,有的时候已经跟不上了。理解层面的东西,有的时候并不是回放能解决的,更多的我觉得是老师举出一些例子,方便大家理解。线上的授课让老师不知道学生听懂与否,就直接照着自己思路来讲了,但感觉线下有的时候老师会换个角度,这个时候就比较容易理解了。
所以总结就是线上各有利弊,对于细节的实现,线上授课更好,因为比较琐碎,但是对于整体架构分析,还是线下授课比较好,因为过于抽象。