OO Unit1 总结分析

郭骐鸣-21373281 学生 2023-03-18 15:29:23

Homework 1

基本架构

参考第一单元的训练任务,我建立了本次作业的基本框架。

首先是解析输入的部分,我根据训练任务中的 Parser 和 Lexer 构建了自己的 Parser 和 Lexer,结构上基本没有改变。

然后是存储表达式的部分,Factor 作为接口,Power、Expr、Term 实现这个接口。

类图

OO 度量

一些细节上的处理

不管是 Expr 和 Term,在存储时我都没有用哈希表的结构,但在表达式化简时,我使用了 Hashmap 结构。考虑到之后各种迭代,我需要对每一个 Term 对象得到一个特异的特征值,只有同类的 Term 才会有相同的特征值。基于学习成本、时间成本等因素,我最后决定使用字符串导出一个 Term 对象的特征值。

对于两个 Term 分别为 3*x*y 和 y*-6*x,这两个 Term 的类型应该是一样的(可以合并的)。我在设计 Term 时已经把常数项单独处理,因此 3、-6 等可以不用考虑,在导出字符串特征值时,应该优先对各个项按照字典序进行排序,否则无法保证同类型 Term 特征值的唯一性。

BUG 分析

我的第一次作业在测试中只出现了一个 BUG,即连续加减号的处理错误。

在做第一次作业时,我一直误以为作业的输入规则与 sympy 的规则相同,因此我认为类似于“+-+5*x”的表达式不会成立。实际上我的认为是错误的,这是我没有认真分析作业书的问题。

这个 BUG 出现在对输入字符串的处理上。我在强侧中提交的代码对字符串的处理为:

    private static String stringPreProcess(String s) {
        return s.replaceAll("[ \r\t]", "")
                .replaceAll("-\\+", "-")
                .replaceAll("\\+-", "-")
                .replaceAll("--", "+")
                .replaceAll("\\+\\+", "+")
                .replaceAll("\\*\\*\\+", "**");
    }

这个函数不能处理三个连续正负号的情况。BUG 修复中,我将替换重复了一次:

    private static String stringPreProcess(String s) {
        return s.replaceAll("[ \r\t]", "")
                .replaceAll("-\\+", "-")
                .replaceAll("\\+-", "-")
                .replaceAll("--", "+")
                .replaceAll("\\+\\+", "+")
                .replaceAll("-\\+", "-")
                .replaceAll("\\+-", "-")
                .replaceAll("--", "+")
                .replaceAll("\\+\\+", "+")
                .replaceAll("\\*\\*\\+", "**");
    }

即可通过强测所有点以及 HACK 的测试点。

BUG 测试

我在 Python 中设计了自己的数据生成器,其生成逻辑为:

def generate(recursion=1):
    ans = ''
    expr_len = random.randint(1, 6)
    for i in range(expr_len):
        item_len = random.randint(1, 4)
        ans += str(random.randint(-5, +5))
        for j in range(item_len):
            ans += '*'
            if recursion > 0 and random.randint(0, 4) == 3:
                ans += '('
                ans += generate(recursion - 1)
                ans += ')'
                if random.randint(0, 4) == 3:
                    ans += '**'
                    if random.randint(0, 1) == 0:
                        ans += '+'
                    ans += str(random.randint(0, 4))
            else:
                if random.randint(0, 4) != 3:
                    ans += value_map[random.randint(0, 2)]
                    if random.randint(0, 4) == 3:
                        if random.randint(0, 4) == 3:
                            ans += '**'
                            if random.randint(0, 1) == 0:
                                ans += '+'
                            ans += str(random.randint(0, 4))
                else:
                    ans += str(random.randint(-10, 10))

        if i != expr_len - 1:
            if random.randint(0, 1) == 1:
                ans += '+'
            else:
                ans += '-'
    return ans

这个数据生成不能覆盖所有的数据,比如上面提到过的连续三个正负号。 

Homework 2

基本架构

这一次作业我算是进行了一次小型的重构。我重新构造了两个接口和一个虚类。

Base 接口:这个接口被所有的表达式相关类实现,它只有一个方法是 multiply。

Irreducible 接口:这个接口被 Sin,Cos 等类实现,这个接口中包含一个方法 innerSimplify。他的设计中实现这个接口的类是拥有内部表达式,并且这个内部表达式的化简不会对外部产生任何影响的。举个例子来说,sin((2*x)) 永远不会被化简为 2*sin(x)*cos(x)。 这个接口以后还可以 implements 到 exp、ln 等类上。

Factor 类:这是一个虚类,所有的因子都继承于这个类。

类图

一些细节上的处理

在处理自定义函数时,我将自定义函数的右边作为一个完整的 Expr 进行解析。在解析为 Expr 后,先将其进行一次展开和化简。当在表达式中遇到自定义函数时,将这个自定函数的 Expr 导出为字符串再进行字符串替换。事实表明,使用字符串替换是简单且高效的自定义函数代入方法。

对于可嵌套的括号,我在 Homework 1 中就支持了这项功能,现在只需要在输入解析中添加递归逻辑即可。

OO 度量

这次作业和 Homework 1 的 OO 度量基本相同。

BUG 分析

此次在互测中表现出的 BUG 是上述细节处理中,将自定函数的 Expr 导出为字符串时未先将其展开和化简。在我的设计中,Expr::toString() 方法只对进过展开化简过的对象有作用。如果 Expr 中存在为 0 的项,那么 toString 方法不会在 0 的前面添加任何符号。因此“2+0+3”未经化简时可能会输出“20+3”的结果。

Homework 3

基本架构

这次对基本架构没有改动。与 Homework 2 相比,我只是在 Base 类中添加了 diff 方法。

类图

 一些细节上的处理

这次要实现的求导功能其实和乘法功能十分相似,任何一种因子或者项都可以进行求导,而求导后不一定能够保证保持原来的类型不变。

OO 度量

此次新添加的 diff 方法在各种复杂度上都很小。

BUG 分析

此次作业在强测、互测中未出现 BUG。

心得体会

设计一个好的程序框架对后续的扩展开发十分重要。

我在迭代 Homework 2 时,对各个类的共性、异性进行过不同角度的分类处理。这耗费了我很多时间,也曾经让我的内心一团乱麻(那是真的麻)。但是确定完架构后,不管是细节的实现还是 Homework 3 的迭代,都变得非常的容易。

...全文
30 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

444

社区成员

发帖
与我相关
我的任务
社区描述
2023年北京航空航天大学《面向对象设计与构造》课程博客
java 高校 北京·海淀区
社区管理员
  • 被Taylor淹没的一条鱼
  • 0逝者如斯夫0
  • Mr.Lin30
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧