OO第一单元总结与反思
摘要
本单元作业分为三次
HW1:本次作业,需要完成的任务为简单多项式导函数的求解。
HW2:本次作业,需要完成的任务为包含简单幂函数和简单正余弦函数的导函数的求解。
HW3:本次作业,需要完成的任务为包含简单幂函数和简单正余弦函数的导函数及其组合的求解。
第一次作业
OO第一次作业来得比预想的要悄无声息,
带着脑中早已相好的思路当天晚上就完成了基本功能(没有WF属实很爽!)
由于只有多项式,根据a*x**b的基本形式,
很容易就可以想到用HashMap
以指数为key,系数为value存储每一项,
如此一来既能轻松求导又便于合并同类项。
关于输入,由于没有WF,因此直接处理成标准形式以便解析:
首先,直接去掉空白符,排除干扰。
其次,处理符号,使得项与项之间仅被
+
分隔,特别注意-
的处理。然后,利用
String
对象的replace
方法处理每一项为a*x**b的基本形式。最后利用正则表达式提取系数和指数便万事大吉。
本次作业性能分仅取决于输出的正确字符串的长度,因此必须关注以下几点
合并同类项
系数1不输出,-1*仅保留-号
指数为1不输出
0项直接跳过
正项先输出(毕竟负项会在最开始多个负号)
(第一次作业性能分简直白给!)
本次作业UML类图
一main到底如今看来实在丑陋
本次作业度量分析
本次作业一共码了145行,完全没有脱离C语言程序设计的思路,
直接拿static方法当函数,洋洋洒洒100多行,敲得倒是舒爽
一点也不OO!!
Project Name | Package Name | Type Name | Method Name | LOC | CC | PC |
---|---|---|---|---|---|---|
OO_Unit1_work1 | (default package) | MainClass | StrToMap | 25 | 4 | 0 |
OO_Unit1_work1 | (default package) | MainClass | getResult | 18 | 4 | 1 |
OO_Unit1_work1 | (default package) | MainClass | output | 65 | 14 | 1 |
OO_Unit1_work1 | (default package) | MainClass | inputHandle | 22 | 4 | 0 |
OO_Unit1_work1 | (default package) | MainClass | main | 9 | 2 | 1 |
本次作业的复杂度均来源于output方法,此方法为了实现优化,
用了多重if-else,而且实现的功能繁多,也是bug出现的高频地段!
Class | OCavg | WMC |
---|---|---|
MainClass | 5.6 | 28 |
简单粗暴,方法多复杂,整个项目就多复杂 -_- 一main到底真的没什么好说的
第二次作业
此次作业在上次作业的基础上增加了三角函数,由于上次作业采用的是a*x**b的架构,
因此此次考虑采用a*x**b*sin(x)**c*cos(x)**d并用单独一个item类储存四元组的架构,
本次作业的checkformat部分采用了部分正则+自动机的模式,
用各个因子的正则表达式一段一段逐步匹配表达式,
用于分隔的符号则用自动机来识别,
checkformat无误之后的操作与第一次作业相同。
本次作业的UML类图
本次作业的度量分析
本次作业一共码了440行,3个类以及25个方法。
Project Name | Package Name | Type Name | Method Name | LOC | CC | PC |
---|---|---|---|---|---|---|
HW2 | com.lkl.oo | Item | Item | 5 | 1 | 3 |
HW2 | com.lkl.oo | Item | Item | 6 | 1 | 4 |
HW2 | com.lkl.oo | Item | setCnst | 3 | 1 | 1 |
HW2 | com.lkl.oo | Item | getCnst | 3 | 1 | 0 |
HW2 | com.lkl.oo | Item | getString | 36 | 10 | 0 |
HW2 | com.lkl.oo | Item | getDiff | 20 | 5 | 2 |
HW2 | com.lkl.oo | Item | equals | 12 | 4 | 1 |
HW2 | com.lkl.oo | Item | hashCode | 3 | 1 | 0 |
HW2 | com.lkl.oo | Item | caseAll | 5 | 1 | 3 |
HW2 | com.lkl.oo | Item | case1 | 18 | 4 | 2 |
HW2 | com.lkl.oo | Item | case2 | 9 | 3 | 2 |
HW2 | com.lkl.oo | Item | case3 | 9 | 3 | 2 |
HW2 | com.lkl.oo | Item | simplify | 5 | 1 | 2 |
HW2 | com.lkl.oo | Judge | Judge | 8 | 1 | 2 |
HW2 | com.lkl.oo | Judge | exitWF | 4 | 1 | 0 |
HW2 | com.lkl.oo | Judge | nextStart | 30 | 8 | 3 |
HW2 | com.lkl.oo | Judge | func | 9 | 2 | 2 |
HW2 | com.lkl.oo | Judge | judge | 32 | 9 | 0 |
HW2 | com.lkl.oo | Main | StrToMap | 38 | 8 | 0 |
HW2 | com.lkl.oo | Main | merge | 14 | 5 | 2 |
HW2 | com.lkl.oo | Main | simple | 17 | 5 | 1 |
HW2 | com.lkl.oo | Main | getResult | 13 | 3 | 1 |
HW2 | com.lkl.oo | Main | output | 57 | 13 | 1 |
HW2 | com.lkl.oo | Main | inputHandle | 29 | 3 | 0 |
HW2 | com.lkl.oo | Main | main | 25 | 2 | 1 |
可以看到,最复杂方法有两个,一个是item类的toString
,
还有一个是output
方法(代码行数57),
这两个方法有一个共同点就是if-else结构很多,这也是出于优化考虑,
当然也确实没能在优化和架构之间达到完美的协调。
Class | OCavg | WMC |
---|---|---|
com.lkl.oo.Item | 2.77 | 36 |
com.lkl.oo.Judge | 4.2 | 21 |
com.lkl.oo.Main | 5.57 | 39 |
本次作业依然做的不是很OO,虽然不像第一次作业那么极端(一main到底),
但说实话,我只是进行了刻意的封装,
即便这样,处理起来确实感受到了相比于第一次作业来说的一些便利。
另外,MainClass类承担太多功能的设计属实让我觉得不舒服了,不仅仅是美观的问题,
还总是给我一种面向过程编程的残念,过多的static方法真的不是个好习惯。
因此,我决定结合实验课、研讨课所学,在第三次作业上彻底OO一把。
第三次作业
此次作业在上次作业的基础上增加了表达式嵌套,由于上次作业采用的是:
a*x**b*sin(x)**c*cos(x)**d的用单独一个item类储存四元组的架构,
显然已经无法支持嵌套的递归解析了。故本次进行和预想的一样进行了大重构。
在开始作业之前其实就已经想好了本次的架构:
自顶向下分析,逐层解析表达式,根据加减、乘、复合求导规则构建起一棵表达式树。
如此,表达式树的叶节点将会是基本因子。
因此求导仅需实现各个求导规则以及基本因子的求导模式即可递归完成整个表达式的求导。
另外,本次作业的checkformat部分依旧采用了部分正则+自动机的模式,
仅需在遇到左括号时多一步递归操作即可。
本次作业的UML类图:
因为每种求导规则以及基本因子都具有求导功能,因此统一实现求导接口,创建表达式的工作就交由抽象工厂来完成。
本次作业的度量分析
本次作业一共码了672行,包括5个包,11个类和46个方法
Project Name | Package Name | Type Name | Method Name | LOC | CC | PC |
---|---|---|---|---|---|---|
OO_Unit1_work3 | exception | WrongFormatException | WrongFormatException | 2 | 1 | 0 |
OO_Unit1_work3 | exception | WrongFormatException | WrongFormatException | 3 | 1 | 1 |
OO_Unit1_work3 | factory | ExpFactory | ExpFactory | 4 | 1 | 2 |
OO_Unit1_work3 | factory | ExpFactory | addSimplify | 18 | 6 | 2 |
OO_Unit1_work3 | factory | ExpFactory | Add | 29 | 9 | 0 |
OO_Unit1_work3 | factory | ExpFactory | Mult | 39 | 12 | 0 |
OO_Unit1_work3 | factory | ExpFactory | Compound | 11 | 3 | 0 |
OO_Unit1_work3 | factory | ExpFactory | findtype | 9 | 3 | 2 |
OO_Unit1_work3 | factory | ExpFactory | combine | 10 | 2 | 2 |
OO_Unit1_work3 | factory | ExpFactory | nextItem | 10 | 2 | 2 |
OO_Unit1_work3 | factory | ExpFactory | createExpr | 56 | 10 | 1 |
OO_Unit1_work3 | factory | Factory | Add | 0 | 1 | 0 |
OO_Unit1_work3 | factory | Factory | Mult | 0 | 1 | 0 |
OO_Unit1_work3 | factory | Factory | Compound | 0 | 1 | 0 |
OO_Unit1_work3 | inputhandler | InputHandler | checkbrace | 11 | 2 | 1 |
OO_Unit1_work3 | inputhandler | InputHandler | inputHandle | 29 | 3 | 1 |
OO_Unit1_work3 | inputhandler | InputHandler | braceMatching | 17 | 5 | 3 |
OO_Unit1_work3 | inputhandler | Judge | exitWF | 3 | 1 | 0 |
OO_Unit1_work3 | inputhandler | Judge | nextStart | 36 | 10 | 4 |
OO_Unit1_work3 | inputhandler | Judge | func | 9 | 2 | 6 |
OO_Unit1_work3 | inputhandler | Judge | braceCheck | 18 | 4 | 1 |
OO_Unit1_work3 | inputhandler | Judge | checkTheRoot | 24 | 6 | 4 |
OO_Unit1_work3 | inputhandler | Judge | checkIndex | 6 | 2 | 1 |
OO_Unit1_work3 | inputhandler | Judge | judge | 57 | 14 | 1 |
OO_Unit1_work3 | item | Add | Add | 4 | 1 | 2 |
OO_Unit1_work3 | item | Add | getDiff | 3 | 1 | 0 |
OO_Unit1_work3 | item | Add | toString | 26 | 8 | 0 |
OO_Unit1_work3 | item | Compound | Compound | 4 | 1 | 2 |
OO_Unit1_work3 | item | Compound | isConst | 3 | 1 | 1 |
OO_Unit1_work3 | item | Compound | isX | 3 | 1 | 1 |
OO_Unit1_work3 | item | Compound | getDiff | 14 | 3 | 0 |
OO_Unit1_work3 | item | Compound | toString | 18 | 4 | 0 |
OO_Unit1_work3 | item | Expression | getDiff | 0 | 1 | 0 |
OO_Unit1_work3 | item | Factor | zero | 3 | 1 | 0 |
OO_Unit1_work3 | item | Factor | one | 3 | 1 | 0 |
OO_Unit1_work3 | item | Factor | Factor | 4 | 1 | 2 |
OO_Unit1_work3 | item | Factor | getType | 3 | 1 | 0 |
OO_Unit1_work3 | item | Factor | getNum | 3 | 1 | 0 |
OO_Unit1_work3 | item | Factor | getDiff | 42 | 11 | 0 |
OO_Unit1_work3 | item | Factor | toString | 38 | 11 | 0 |
OO_Unit1_work3 | item | Mutiply | Mutiply | 4 | 1 | 2 |
OO_Unit1_work3 | item | Mutiply | getE2 | 3 | 1 | 0 |
OO_Unit1_work3 | item | Mutiply | getE1 | 3 | 1 | 0 |
OO_Unit1_work3 | item | Mutiply | getDiff | 5 | 1 | 0 |
OO_Unit1_work3 | item | Mutiply | toString | 9 | 3 | 0 |
OO_Unit1_work3 | (default package) | MainClass | main | 21 | 2 | 1 |
从以上参数可以看出复杂的方法主要是toString
(因为有许多if-else做浅优化)、
checkformat的judge
(57行)和nextstart
(一个方法功能过多/自动机if-else太多)以及createExpr
(56行,也是功能太多,一个方法创造所有类型因子以及最终整合成一个表达式)。
Class | OCavg | WMC |
---|---|---|
MainClass | 2 | 2 |
exception.WrongFormatException | 1 | 2 |
factory.ExpFactory | 5.33 | 48 |
inputhandler.InputHandler | 3.33 | 10 |
inputhandler.Judge | 5.57 | 39 |
item.Add | 3.33 | 10 |
item.Compound | 2 | 10 |
item.Factor | 4.14 | 29 |
item.Mutiply | 1.4 | 7 |
上升到类的高度可以看出难度主要集中在表达式的输入解析处理,求导反而是较轻松的一部分。
本次作业疏忽了对于WF的检查,导致强测wa了一个点,互测未被hack。
说是疏忽了,其实还是因为judge方法写的太过于冗杂,导致一个很明显的错误未被发现。
这提醒我今后要分散功能,尽量避免长方法,另外在细节方面必须做足测试,切忌轻敌。
测试及bug杀虫
本次作业仅被第三次强测hack了一个点,总体还算满意
本次作业的测试方面主要是利用python的xeger库使用正则表达式生成数据
为了尽量做到可能性全覆盖,需要仔细研究指导书的形式化描述以构造正确的正则表达式
不足的一点是WF方面不是做的特别好,险些造成第二次作业无效,
也导致了第三次作业wa了一个点。
对于互测,我采取的策略是首先对屋内其他人的代码进行覆盖性测试,
此时或多或少能得到一些错误数据,但还不清楚对方bug在哪
此时转移到出错的代码上,不断削减出错数据的复杂度,同时做到此代码仍然复现bug
最终定位出错部分并进行调试,同时阅读代码,取其精华去其糟粕,
最后把此bug修复继续压力测试以期发现非同质bug。
我不是,我只是在友好的帮忙debug
心得与体会
可以看到,我在三次作业的迭代过程中,OO思想越来越深入代码,
第三次可以说是我最OO的一次了
通过这三次作业以及两次实验加一次研讨,我确实学习到了许多
git操作、工厂方法、行为抽象和数据抽象已经明确了其相应概念且能付诸实践
代码风格、设计理念也已经有了初步的认识,特别是高内聚低耦合的思想已经根深蒂固了
另外不得不提的是markdown语言的使用也不知不觉地精通了!!
唯一遗憾的是,出于多方面考虑懒、怕出bug,我在优化方面做的不是很好
都是做了浅优化,浅尝辄止,终归还是设计能力的不足,不敢保证自己的代码在多方面做到最好。
对比了优秀代码,我真是自愧不如,看来我该做的努力还是很多的,不仅仅是为了应付作业。
希望在下一单元不要留下什么遗憾,多学多看多问!重新做人