其他分享
首页 > 其他分享> > OO2022第一单元个人总结

OO2022第一单元个人总结

作者:互联网

前言

本文是对第一次面向对象课程作业的总结,文章首先总结了本次作业我的总体架构思路,接着分析了三次作业中我的架构迭代历程,之后对于我的最终架构给出了代码度量分析,且分析了架构的优缺点。之后文章分析了在Hack过程中的收获,以及在本次作业设计,编写中我学到的东西,尤其是关于深浅克隆这一部分我分享了我认为比较好的一些资料,和我自己的理解,希望uu们不要跟我一样在这一知识点再犯错误。最后文章阐述了本次作业中我的心得体会。文章如有错误,谢谢指正!


一.总体架构思路

在本次作业中,我们的最终需求是对一个表达式进行化简计算,并进行一些必要的合并与优化。然而要进行计算,首要任务是进行表达式的解析。总而言之,要完成解析和计算这两个需求,我设计了如下架构,我的架构简而言之是:递归向下解析,自底向上计算,输出前再进行合理优化。形象化的表示一下就是如下的流程图。

在我的架构中,将表达式抽象为了四个层次,在作业指导书中,由于已经给出了表达式的形式化表示,我们可以很容易抽象出以下层次:

有了以上这些层次,我们首先对输入进行递归向下解析,解析出表达式中包含哪些层次,经过自底向上的计算,可以得到每个层次的[Elements]数组,最终得到的Expr表达式的[Elements]数组便是我们得到的初步计算结果,经过合并同类项等优化便可以进行输出。

二.迭代过程

在这一部分简要阐述了我的三次迭代心路历程,其中并没有放UML类图,因为三次作业我没有做大规模的重构,三次作业的UML类图重复相似部分较多,我将会在代码度量分析一节中分析UML类图,其中标明了每次作业的新增与修改部分。

2.1第一次作业

在第一次作业中,首次上手java作业打了我一个措手不及,因为之前写的都是流程式的程序,开始时构思面向对象式的架构没有很好地思路,属于是一头雾水了,花了很多时间去理解题目并和同学交流,并且在助教给的训练项目中也得到了一些启发,最终构思了上述的程序架构。

HW1

2.2第二次作业

在本次作业中,新增了自变量函数,求和函数,三角函数三种因子,这要求我们对新增的这三种因子进行识别与计算。此外,由于在解析f与sum时需要进行自变量的替换,替换后可能出现表达式括号嵌套的形式,这要求架构中的解析过程要支持嵌套括号的形式,这是本次作业一个潜在的需求。

HW2

2.3第三次作业

在本次作业中,新增了函数间的相互调用,三角函数内嵌套等新需求。关于函数之间的相互调用,在HW2中对于自定义函数的处理方法是,进行自变量的替换后直接看做表达式进行处理,因此HW2架构已经可以实现函数之间的互调用。在本次作业中主要实现了三角函数的内嵌套,相较于第二部分修改较少。

三.代码度量分析

先放一下HW3最终的UML类图

之前我并未接触过代码度量的含义,了解之后学习到其一些指标含义如下:

  1. CogC:认知复杂度,反应一个方法的可理解性,循环分支等结构越多,可理解性越差,数值越高。
  2. ev(G):基本复杂度是用来衡量程序非结构化程度的。
  3. Iv(G):模块设计复杂度是用来衡量模块判定结构,即模块和其他模块的调用关系,越高说明模块和其他模块之间的调用关系复杂,耦合程度越高.
  4. v(G):是用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数,数值越高说明程序越难以维护

方法复杂度

PreFun.printans(ArrayList) 48.0 3.0 16.0 17.0
PreFun.mergecs2(ArrayList) 42.0 10.0 9.0 12.0
Factor.parse() 31.0 4.0 12.0 15.0
Element.matchcs(Element) 30.0 9.0 10.0 12.0
Element.Element(String) 28.0 1.0 15.0 18.0
Fun.parse() 26.0 3.0 10.0 11.0
PreFun.neg(ArrayList) 19.0 1.0 8.0 8.0
Expr.parse() 12.0 1.0 8.0 9.0
Term.parse() 12.0 1.0 7.0 8.0
PreFun.addcos(StringBuilder, Element) 10.0 1.0 6.0 6.0
PreFun.addsin(StringBuilder, Element) 10.0 1.0 6.0 6.0
PreFun.issingle(ArrayList) 8.0 5.0 11.0 12.0
Cos.cossequal(ArrayList, ArrayList) 7.0 4.0 3.0 4.0
Element.elementsequal(ArrayList, ArrayList) 7.0 4.0 3.0 4.0
PreFun.mergecs(ArrayList) 7.0 1.0 5.0 5.0
Sin.sinsequal(ArrayList, ArrayList) 7.0 4.0 3.0 4.0

(由于方法较多,篇幅限制只列出了分析结果中数值较大,标红的部分数据。)

接下来进行代码度量结果的分析

四.Hack与被Hack

4.1 个人Bug发现与分析

关于本次作业的Bug较多的集中在深克隆与浅克隆这个问题上,这可能与我的代码架构有关,在对ArrayList操作时使用了较多的add方法。

在一次作业中我首次遇到了深克隆与浅克隆的问题,但在课下时我已经发现了这个Bug并予以解决。但在第二次作业时,又再一次出现了深克隆浅克隆的问题,这个Bug原因是我在计算[Elements]数组时为了实现合并两数组的[sin][cos],直接采用了add方法,因为第二次作业我并未对Sin,Cos内部进行操作,所以当时我认为直接采用add方法是正确的,简便的,因而这个Bug在第二次作业时并没有显现。

然而在第三次作业中,在优化部分我新增了二倍角优化方法,直接对Sin,Cos内部项的系数进行了操作,此时我忽略了之前采用add方法合并数组时采用了浅克隆而非深克隆,直接引发了第二次作业所埋下的隐患。以后再也不瞎优化了(bushi,所以有时候不优化,保证正确性可能会更好一点。不过言归正传,这个Bug十分隐蔽,我在课下并没有发现,导致一个强测点直接寄掉。

这个Bug出现的原因有二:

4.2 互测他人Bug发现与分析

本次互测发现了其他同学如下几个Bug

五.我学到的

5.1 深克隆与浅克隆

深克隆与浅克隆在本次作业中对我的“身心摧残”已在上文阐述,接下来需要进一步深入理解深浅克隆的区别与实现,以防以后出现类似的问题。

1.首先我们需要知道什么时候我们在进行克隆?

2.深浅克隆的区别是什么?

3.我在深浅克隆中犯的错误

4.如何进行规范的克隆?

[(40条消息) Java对象克隆——浅克隆和深克隆的区别_JeffCoding的博客-CSDN博客_浅克隆和深克隆的区别]

java 深克隆(深拷贝)与浅克隆(拷贝)详解 - mindcarver - 博客园 (cnblogs.com)(这一篇比较长,其实上一篇对于理解和实用来说就完全足够)

我来简单总结一下,java中已经为类准备了clone方法,我们不需要重复造轮子,要实现规范的clone,还需要以下两点:

接下来,我认为重要的是理解为什么要重写Clone方法,对于只包含基本数据类型属性的类来说,clone方法完全够用,不需重写,clone后的新旧对象互不影响。重写Clone方法是为了应对类中包含了其他自定义的对象属性这种情况(比如在本次HW2作业中,我在SinCos类中包含了[Elements]数组作为属性),这时Clone方法在拷贝这个属性时,拷贝的只是引用类型的指向,也就是我们所说的浅拷贝,后续再对这个属性进行操作时,便会在不经意间对新旧对象同时操作,这样的Bug很难查找出来,因此在设计时就要予以避免。

如何进行避免?方法也很简单,只需要在本类中修改重写的Clone方法,包含的其他自定义的对象里面也重写Clone方法,多个浅拷贝便可以实现深拷贝。引用第一篇博客中的例子如下(Customer类中包含顾客地址Address类),在两个类中均重写Clone方法,之后再调用Clone方法可以对Customer深克隆。

//Address
@Override  
public Address clone() throws CloneNotSupportedException {  
    return (Address) super.clone();  
}  
//Class Customer(Address是Customer的一个属性成员)
@Override  
public Customer clone() throws CloneNotSupportedException {  
    Customer customer = (Customer) super.clone();  
    customer.address = address.clone();  
    return customer;  
}  

总而言之,我认为对于java深浅拷贝的这样一种理解很准确:Java中定义的clone没有深浅之分,都是统一的调用Objectclone方法。为什么会有深克隆的概念?是由于我们在实现的过程中刻意的嵌套了clone方法的调用。也就是说深克隆就是在需要克隆的对象类型的类中全部实现克隆方法

5.2 去哪里找Bug

这一点其实在理论课上有讲,我认为总结的是在太好了,这里再将其罗列一下。

可以看到,我属于是精准踩雷有木有。所以在静态检查时,可以有意识的去思考以上检查要点,这能帮助我们更快更好的找到Bug,虽然不能覆盖所有Bug,但我觉得可以覆盖很大一部分非理解题意错误而导致的Bug。

5.3 测试数据

主要采用随机测试的方式,手动构造了一些我认为比较容易Error和Wrong Answer的边界数据,虽然也有一定的Hack量,但Hack成果并没有很显著,如果写个自动评测机可能会更好一点,周末开着自动评测机让其自动Hack,自己可以做其他的事情,多是一件美事啊。所以在这里我反思一下,下一次一定要写个自动评测机,下次一定。

六. 心得体会

通过第一单元的作业,我有以下几点收获

标签:总结,架构,克隆,作业,OO2022,解析,方法,Bug,单元
来源: https://www.cnblogs.com/Shl518/p/16057134.html