301
社区成员
发帖
与我相关
我的任务
分享代码共有 24 个类和 1 个接口构成,具体代码量如下图。主要代码量由计算时使用的多项式类和单项类组成。

对类的复杂度进行分析,具体如下。发现主要复杂的部分为 Lexer,Parser,Calc,Monomial 和 Poly,这也恰好对应对应了任务中的不同板块的主要类

代码的类图如下,个人认为代码对类的划分和分工是较为清晰的,能够较好的分离不同的类。

第一次作业时搭下了比较好的基础,将整个任务分为了解析和计算两个完全分离的部分。
解析部分由 Factor 及其实现类和 Term,Parser 和 Lexer 解决,采用递归下降的方法,按形式化定义将解析式一层一层的解析,最后得到一个便于计算的结构,此处使用了后缀表达式表示。
计算部分由 Operator 及其子类和 Calc 类解决,先有 Calc 类将后缀表达式表示成 Operator 类的表达式树,再在树上进行答案的计算。
此处,将不同的运算用 Operator 进行统一的表示,并计算是一个比较好的做法,这样的架构使得后面添加新的运算只需要对新运算进行实现即可。
而为了便于实现
由第一次作业搭建好的基础后,第二次作业只需要新加入 exp 和 自定义函数。
对于 exp 只需要对其建立新的 exp 类及其对应的运算即可
对于自定义函数,将其看做一种新的 Operator,只是其计算方法是根据输入决定的。而这个计算方法是一个在代值进行计算的过程,是可以直接在表达式树上完成的,所以在我的架构下直接对新的函数进行解析,计算时在其对应表达式树计算即可。这样的方法对已有部分充分的重复利用,只需要很少的改动即可完成
新加入求导算子,得益于优秀的将不同算子全部看做 Operator 的架构,只需要添加求导的计算方法即可,无需对代码整体改动。
纵观几次作业,该架构中将解析和计算彻底分离,所以需要每次考虑的内容其实很少。而将不同算子视作 Operator 进行计算的方法,也使得每次新增运算无需对代码进行大规模更改,只需要简单的实现该运算即可,具有很强的扩展性。
由于良好的代码架构,我在整个过程中并没有什么 bug 出现,可以很好的解决问题。
在整个互测过程中,我并没有找到一个较好的思路去发掘他人 bug 的方法,只能通过对拍的方法进行检测
整个过程中我了解到了合适的架构和思路对于代码的迭代和实现的重要意义,通过面向对象的思路进行代码的构建才能使代码的可迭代性更好