第一次作业

程序架构

hw1uml

最初的设想是用Expr->Term->Factor的架构,但是由于刚刚接触 Java,还不懂接口等方法,不会处理表达式因子,所以直接把Factor看成了一个项,每个Factor都是a*x^n的形式。

我在Factor里分别创建了symbol指示这一项的正负号,index指示幂次,variable指示变量(在本单元作业中是只有 x,当时考虑可拓展性加了variable,在第二次作业的迭代中删了),constant指示系数

于是,在这样的的架构下,最终输出的就是多个Factor相加的形式,也就是Expr。这样一来Term的设计就显得很多余,实际上Term也确实在输出时没有起到作用,Term在我的架构里很像辅助Expr乘法计算的一个中间量,我们把Term也看作是一个表达式,每读取一个Term就进行一次Term*Term,处理完这一级全部的乘法之后就返回上一级,在返回前,Term已经是多个Factor相加的表达式,把Term里的所有Factor都加到Expr里,再合并同类项就可以完成拆括号。(实际上可以给TermFactor换个名字,会方便理解一点)

Processing

完成了字符串的预处理和后处理

预处理:
  1. 删除空格和制表符
  2. 删除前导零
  3. 将连续的加减号(最多三个)替换为单个加减号
  4. *+^+(++删除
  5. 在每个左括号前添加 1*,确保括号前有乘法因子
  6. 如果字符串以加号开始,则移除它
后处理(在toString中的处理不太好,所以做了后处理)
  1. 将连续的加减号替换为单个加减号
  2. 移除+0的项

Lexer

沿用了training中的Lexer模块,进行字符串解析,解析出 数字字符串 字母字符串 符号字符串

Parser

采用了递归下降的写法,其架构如下

public Expr parseExpr() {
// ...parseExpr
while (lexer.peek().equals("+") || lexer.peek().equals("-")) {
// ...parseExpr
}
return expr;
}

public Term parseTerm() {
// ...parseFactor
while (lexer.peek().equals("*")) {
// ...parseFactor
}
return term;
}

public Term parseFactor() {
if (lexer.peek().equals("(")) {
...... // 读取表达式因子
}
else if (lexer.peek().equals("x")) {
...... // 读取变量因子
}
else if (lexer.peek().matches("\\d+")) {
...... // 读取常数因子
}
return term;
}

需要说明的是,这里parseFactor的返回值是Term类。这是由于我在这里进行了表达式因子的幂运算,返回的是ArrayList<Factor>,我又不希望再在Factor里加入更繁琐的ExprTerm,所以如果处理的是变量因子常数因子,返回的Term size==1,这样的设计可以使结构更加简单。

Expr

表达式类

  • 包含一个属性ArrayList<Factor>

  • 实现了addTermaddFactorsimplifyExpr的方法

addTerm:把Term中所有的Factor都通过调用addFactor加到Expr

addFactor:把Factor加到Expr

simplifyExpr:化简表达式(合并同类项),比较每个Factorx的幂次是否相同,相同的就系数相加,不同的就添加一个新的Factor

Term

乘法计算的表达式

  • 包含一个属性ArrayList<Factor>
  • 实现了multiplypowaddAll的方法

multiply:乘法运算,计算表达式 Term 和表达式 Term 相乘得到的新表达式

pow:计算 Term 自己的幂次运算,即将乘法运算进行 index 次

addAll:把parseFactor得到的Term中的所有Factor,全都加到当前的Term

Factor

  • 包含四个属性,symbol:这一项的正负号,index:幂次,variable:变量,constant:系数

  • 主要实现了mergeFactor的方法

mergeFactor:把两个Factor合并,系数相加,幂次不变,符号和计算后的系数相同。

复杂度分析

Method CogC ev(G) iv(G) v(G)
expr.Expr.addFactor(Factor) 0.0 1.0 1.0 1.0
expr.Expr.addTerm(Term) 0.0 1.0 1.0 1.0
expr.Expr.Expr() 0.0 1.0 1.0 1.0
expr.Expr.getFactors() 0.0 1.0 1.0 1.0
expr.Expr.simplifyExpr(Expr) 4.0 1.0 3.0 3.0
expr.Expr.toString() 4.0 2.0 3.0 3.0
expr.Factor.Factor(int, int, String, BigInteger) 0.0 1.0 1.0 1.0
expr.Factor.getConstant() 0.0 1.0 1.0 1.0
expr.Factor.getIndex() 0.0 1.0 1.0 1.0
expr.Factor.getSymbol() 0.0 1.0 1.0 1.0
expr.Factor.getVariable() 0.0 1.0 1.0 1.0
expr.Factor.mergeFactor(Factor) 3.0 1.0 2.0 3.0
expr.Factor.toString() 17.0 2.0 10.0 11.0
expr.Term.add(Factor) 0.0 1.0 1.0 1.0
expr.Term.addAll(Term) 0.0 1.0 1.0 1.0
expr.Term.addFactor(Factor) 0.0 1.0 1.0 1.0
expr.Term.getFactors() 0.0 1.0 1.0 1.0
expr.Term.multiply(Term) 7.0 1.0 4.0 5.0
expr.Term.pow(Expr, Integer) 6.0 1.0 6.0 6.0
expr.Term.size() 0.0 1.0 1.0 1.0
expr.Term.Term() 0.0 1.0 1.0 1.0
expr.Term.toString() 4.0 2.0 3.0 3.0
Lexer.getConstant() 2.0 1.0 3.0 3.0
Lexer.getVariable() 2.0 1.0 3.0 3.0
Lexer.Lexer(String) 0.0 1.0 1.0 1.0
Lexer.next() 4.0 2.0 4.0 5.0
Lexer.peek() 0.0 1.0 1.0 1.0
MainClass.main(String[]) 0.0 1.0 1.0 1.0
Parser.parseExpr() 5.0 1.0 5.0 5.0
Parser.parseFactor() 10.0 2.0 8.0 8.0
Parser.Parser(Lexer) 0.0 1.0 1.0 1.0
Parser.parseTerm() 1.0 1.0 2.0 2.0
Processing.postProcess(String) 0.0 1.0 1.0 1.0
Processing.preProcess(String) 1.0 1.0 2.0 2.0
Total 70.0 39.0 78.0 82.0
Average 2.0588235294117645 1.1470588235294117 2.2941176470588234 2.411764705882353

本次作业的架构比较简单,只有expr.Factor.toString()方法的复杂度较高,这是因为我在这个方法里做了较多的判断逻辑,如幂次为 0 时 x 不输出 系数输出。我在输出 0 输出 1 的时候都做了一些特判,是因为我担心自己在其他地方的赋值不够规范,但其实有一部分判断是冗余的

Class OCavg OCmax WMC
expr.Expr 1.6666666666666667 3.0 10.0
expr.Factor 2.4285714285714284 9.0 17.0
expr.Term 2.111111111111111 6.0 19.0
Lexer 2.2 5.0 11.0
MainClass 1.0 1.0 1.0
Parser 3.75 8.0 15.0
Processing 1.5 2.0 3.0
Total 76.0
Average 2.235294117647059 4.857142857142857 10.857142857142858

其中 Parser 类的复杂度较高,主要是由于解析表达式时有较多的判断逻辑,判断因子是哪个因子等

image-20240321014951400

本次作业的码量不算大,主要是架构的设计比较花费时间。以及我没选 OOP,花了很多时间来熟悉和读懂 Java,wwwwww…

Bug 分析

  • 本次作业中,我的程序在强测和互测中都没有出现 bug

  • 我在互测环节 hack 了房内的两名同学,测试点分别是(1)*-7(该同学的程序会输出7)和x+(x^3+x)^6

    • 我借用了往届学长在 GitHub 开源的评测机Toby-Shi-cloud/OOAutoTest:,经过修改后使之符合本次作业要求
    • 通过自动打包,自动生成数据以及借用 python sympy 包自动评测的方式,测试自己的程序和房内同学的程序

性能优化分析

在整个单元我都没有在性能优化上做太多的实现,主要是担心性能优化考虑的不到位导致强测过不了,或者是性能优化导致程序可拓展性降低,不利于后续的迭代。

在第一周作业中,我把+0的项都删掉了,同时,由于我的架构天然的会把x*x*...*x转化成x^n故而省略了这一步的优化

由于时间紧促,我也并没有把+项先输出,-项后输出,来省略一个+号,这部分优化我在第二次作业中补上了。

第二次作业

程序架构

hw2uml

在本次作业中新增了括号嵌套、自定义函数和 exp 函数,其中括号嵌套在递归下降的架构中天然适用,不需要考虑

对于自定义函数,我在Lexer里新增了fgh的识别,在Parser里新增了parseSeDeFuction方法,解析自定义函数。我新建了Function类,用于在读入自定义函数时替换 xyz,以及在读入表达式时替换自定义函数。

对于 exp 函数,我在Factor中新增了exp属性,使每个项都以a*x^n*exp(...)的形式存在,我把 exp 的次方都乘到括号内了,使架构简单。

架构迭代

Processing

我删除了后处理,把 0 项不输出和加减号放在了 toString 里进行了处理

由于有新增函数,所以我在预处理部分做了一点更改

预处理:
  1. 删除空格和制表符
  2. 删除前导零
  3. 将连续的加减号(最多三个)替换为单个加减号
  4. *+^+(++删除
  5. 将表达式中的exp替换为1*e
  6. 在每个左括号前添加 1*
  7. 将以 f1*(, g1*(, h1*(, e1*( 开头的字符串替换为 f(, g(, h(, e(,以消除多余的数字 1
  8. 如果字符串以加号开始,则移除它
FuncProcess

用于在读取表达式时,将自定义表达式逐层替换(通过递归,先替换最里层的)

Function

  • 新增的类,包含一个属性HashMap<String,String>,用来存储自定义函数,其中 key 是 f/g/h,value 是该自定义函数对应的表达式(我把 xyz 分别替换成了 uvw,防止 x 的替换出现问题)

  • 实现了addFunction getFunctions funcToString方法

addFunction:每读到一个新的自定义函数,就把这个自定义函数加入到 Function(HashMap)里

getFunctions:取出所有的 Function

funcToString:把表达式中的自定义函数替换成带入 xyz 后的字符串

Expr

表达式类

  • 新增了deepCopysortFactorspowExp的方法

deepCopy:深拷贝

sortFactors:对 Factor 排序,+项在前

powExp:exp 幂运算,把幂次和 exp 中的每个项相乘

Factor

  • 包含四个属性,symbol:这一项的正负号,index:幂次,constant:系数,exp:指数函数

  • 实现了deepCopy的方法

  • 修改了mergeFactortoString,加入了对 exp 的合并和输出

复杂度分析

Method CogC ev(G) iv(G) v(G)
expr.Expr.addAllExpr(Expr) 0.0 1.0 1.0 1.0
expr.Expr.addFactor(Factor) 0.0 1.0 1.0 1.0
expr.Expr.addTerm(Term) 0.0 1.0 1.0 1.0
expr.Expr.deepCopy() 1.0 1.0 2.0 2.0
expr.Expr.equals(Expr) 8.0 4.0 6.0 7.0
expr.Expr.Expr() 0.0 1.0 1.0 1.0
expr.Expr.getFactors() 0.0 1.0 1.0 1.0
expr.Expr.isSingleFactor() 8.0 1.0 10.0 11.0
expr.Expr.powExp(Expr, Integer) 1.0 1.0 2.0 2.0
expr.Expr.simplifyExpr(Expr) 9.0 4.0 6.0 6.0
expr.Expr.size() 0.0 1.0 1.0 1.0
expr.Expr.sortFactors() 0.0 1.0 1.0 1.0
expr.Expr.toString() 18.0 2.0 7.0 7.0
expr.Factor.deepCopy() 1.0 1.0 2.0 2.0
expr.Factor.Factor(int, BigInteger, BigInteger, Expr) 0.0 1.0 1.0 1.0
expr.Factor.getConstant() 0.0 1.0 1.0 1.0
expr.Factor.getExp() 0.0 1.0 1.0 1.0
expr.Factor.getIndexX() 0.0 1.0 1.0 1.0
expr.Factor.getSymbol() 0.0 1.0 1.0 1.0
expr.Factor.mergeFactor(Factor) 3.0 1.0 2.0 3.0
expr.Factor.toString() 26.0 2.0 17.0 18.0
expr.Term.add(Factor) 0.0 1.0 1.0 1.0
expr.Term.addAll(Term) 0.0 1.0 1.0 1.0
expr.Term.addFactor(Factor) 0.0 1.0 1.0 1.0
expr.Term.getFactors() 0.0 1.0 1.0 1.0
expr.Term.multiply(Term) 6.0 1.0 4.0 4.0
expr.Term.pow(Expr, Integer) 6.0 1.0 6.0 6.0
expr.Term.simplifyTerm(Term) 9.0 4.0 6.0 6.0
expr.Term.size() 0.0 1.0 1.0 1.0
expr.Term.Term() 0.0 1.0 1.0 1.0
expr.Term.toString() 4.0 2.0 3.0 3.0
Function.addFunction(String, String) 0.0 1.0 1.0 1.0
Function.Function() 0.0 1.0 1.0 1.0
Function.funcToString(String, String, int, String) 3.0 2.0 2.0 5.0
Function.getFunctions() 0.0 1.0 1.0 1.0
Lexer.getConstant() 2.0 1.0 3.0 3.0
Lexer.getVariable() 2.0 1.0 3.0 3.0
Lexer.Lexer(String) 0.0 1.0 1.0 1.0
Lexer.next() 7.0 2.0 6.0 8.0
Lexer.peek() 0.0 1.0 1.0 1.0
MainClass.main(String[]) 1.0 1.0 2.0 2.0
Parser.parseExpr() 5.0 1.0 5.0 5.0
Parser.parseFactor() 15.0 3.0 11.0 12.0
Parser.Parser(Lexer) 0.0 1.0 1.0 1.0
Parser.parseSeDeFunction(Function) 16.0 6.0 8.0 8.0
Parser.parseTerm() 1.0 1.0 2.0 2.0
Processing.funcProcess(String) 30.0 6.0 11.0 11.0
Processing.preProcess(String) 1.0 1.0 2.0 2.0
Total 183.0 74.0 152.0 162.0
Average 3.8125 1.5416666666666667 3.1666666666666665 3.375

Processing.funcProcess(String)expr.Factor.toString()的复杂度较高

主要是因为 funcProcess 里有 for 循环和递归的嵌套,复杂度较高,Factor.toString 中在上次作业的基础上加入了对 exp 的判断,导致复杂度更高了

Class OCavg OCmax WMC
expr.Expr <2.4615384615384617,2.4615384615384617> <7.0,7.0> <32.0,32.0>
expr.Factor <2.875,2.875> <13.0,13.0> <23.0,23.0>
expr.Term <2.4,2.4> <6.0,6.0> <24.0,24.0>
Function <2.25,2.25> <6.0,6.0> <9.0,9.0>
Lexer <2.6,2.6> <7.0,7.0> <13.0,13.0>
MainClass <2.0,2.0> <2.0,2.0> <2.0,2.0>
Parser <5.2,5.2> <11.0,11.0> <26.0,26.0>
Processing <5.0,5.0> <8.0,8.0> <10.0,10.0>
Total <139.0,139.0>
Average <2.8958333333333335,2.8958333333333335> <7.5,7.5> <17.375,17.375>

其中 Parser 类和 Processing 类的复杂度较高,主要是由于解析表达式时有较多的判断逻辑,预处理自定义函数的时候有较多的递归替换

image-20240321161659616

代码增量大概在 300 行以内,在自定义函数的递归替换部分我花了较多的时间

Bug 分析

  • 本次作业中,我在强测中出现了致命的 bug 导致没有进互测房(哭)

  • 我的 bug 主要都出在了字符串预处理的部分,第二周把全部的精力都放在了 exp 上,没有在字符串预处理部分做过多的思考。

    一共修复了 3 个 bug

    1. 修复了-(的问题,将其转换成了-1*(,使之对于我的设计来说是可读的
    2. 修复了自定义函数中无法读入空格的问题,将所有的空格删除,之前程序会因为无法继续读入而超时
    3. 修复了(0+0+……+)^5计算时多个0相乘造成的内存爆炸问题,将其优化为(0)^5

性能优化分析

首先是修改了第一周残留的性能问题。把字符串后处理拿掉了,在expr.Expr.toString()expr.Factor.toString()中进行处理加减号和 0 的输出问题;在化简 Expr 的同时,加入一个 sort 方法,以 symbol 来 sort,使正号的项排序在前,先输出。

本周作业其实是有较多的性能优化可以做的,但我只完成了 exp 中为单个因子时,输出一层括号的优化。此外,我也没有对 exp(0)=1 进行优化,也没有提取公因子 以 exp(…)^n 的形式输出。

第三次作业

程序架构

hw3uml

在本次作业中新增了在自定义函数调用自定义函数和求导的功能

对于在自定义函数调用自定义函数,我在main里每次读取新的自定义函数表达式时,调用一次表达式的自定义函数预处理方法Processing.funcProcess

对于求导,我在Factor中新增了deriveFactor方法,对每个项a*x^n*exp(...)求导。我在Expr中新增了deriveExpr方法,对表达式求导。

架构迭代

Expr

表达式类

  • 新增了deriveExpr方法

deriveExpr:把 expr 中的每一项 factor 求导后得到的 term,都加到记录求导结果的 expr 中

Factor

  • 新增了deriveFactor方法

deriveFactor:对每个a*x^n*exp(...)运用求导法则进行运算,得到每个 factor 的求导结果a*n*x^(n-1)*exp(...)+a*x^n*exp(...)*deriveExpr(...)

复杂度分析

Method CogC ev(G) iv(G) v(G)
expr.Expr.addAllExpr(Expr) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Expr.addFactor(Factor) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Expr.addTerm(Term) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Expr.deepCopy() <1.0,1.0> <1.0,1.0> <2.0,2.0> <2.0,2.0>
expr.Expr.deriveExpr() <1.0,1.0> <1.0,1.0> <2.0,2.0> <2.0,2.0>
expr.Expr.equals(Expr) <8.0,8.0> <4.0,4.0> <6.0,6.0> <7.0,7.0>
expr.Expr.Expr() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Expr.getFactors() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Expr.isSingleFactor() <8.0,8.0> <1.0,1.0> <10.0,10.0> <11.0,11.0>
expr.Expr.powExp(Expr, Integer) <1.0,1.0> <1.0,1.0> <2.0,2.0> <2.0,2.0>
expr.Expr.simplifyExpr(Expr) <9.0,9.0> <4.0,4.0> <6.0,6.0> <6.0,6.0>
expr.Expr.size() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Expr.sortFactors() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Expr.toString() <18.0,18.0> <2.0,2.0> <7.0,7.0> <7.0,7.0>
expr.Factor.deepCopy() <1.0,1.0> <1.0,1.0> <2.0,2.0> <2.0,2.0>
expr.Factor.deriveFactor() <7.0,7.0> <3.0,3.0> <6.0,6.0> <6.0,6.0>
expr.Factor.Factor(int, BigInteger, BigInteger, Expr) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Factor.getConstant() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Factor.getExp() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Factor.getIndexX() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Factor.getSymbol() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Factor.mergeFactor(Factor) <3.0,3.0> <1.0,1.0> <2.0,2.0> <3.0,3.0>
expr.Factor.toString() <26.0,26.0> <2.0,2.0> <17.0,17.0> <18.0,18.0>
expr.Term.add(Factor) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Term.addAll(Term) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Term.addFactor(Factor) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Term.getFactors() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Term.multiply(Term) <6.0,6.0> <1.0,1.0> <4.0,4.0> <4.0,4.0>
expr.Term.pow(Expr, Integer) <6.0,6.0> <1.0,1.0> <6.0,6.0> <6.0,6.0>
expr.Term.simplifyTerm(Term) <9.0,9.0> <4.0,4.0> <6.0,6.0> <6.0,6.0>
expr.Term.size() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Term.Term() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
expr.Term.toString() <4.0,4.0> <2.0,2.0> <3.0,3.0> <3.0,3.0>
Function.addFunction(String, String) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
Function.Function() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
Function.funcToString(String, String, int, String) <3.0,3.0> <2.0,2.0> <2.0,2.0> <5.0,5.0>
Function.getFunctions() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
Lexer.getConstant() <2.0,2.0> <1.0,1.0> <3.0,3.0> <3.0,3.0>
Lexer.getVariable() <2.0,2.0> <1.0,1.0> <3.0,3.0> <3.0,3.0>
Lexer.Lexer(String) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
Lexer.next() <7.0,7.0> <2.0,2.0> <6.0,6.0> <8.0,8.0>
Lexer.peek() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
MainClass.main(String[]) <1.0,1.0> <1.0,1.0> <2.0,2.0> <2.0,2.0>
Parser.parseDerive() <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
Parser.parseExp() <1.0,1.0> <1.0,1.0> <2.0,2.0> <2.0,2.0>
Parser.parseExpr() <5.0,5.0> <1.0,1.0> <5.0,5.0> <5.0,5.0>
Parser.parseFactor() <14.0,14.0> <4.0,4.0> <11.0,11.0> <12.0,12.0>
Parser.Parser(Lexer) <0.0,0.0> <1.0,1.0> <1.0,1.0> <1.0,1.0>
Parser.parseSeDeFunction(Function) <16.0,16.0> <6.0,6.0> <8.0,8.0> <8.0,8.0>
Parser.parseTerm() <1.0,1.0> <1.0,1.0> <2.0,2.0> <2.0,2.0>
Processing.funcProcess(String) <31.0,31.0> <6.0,6.0> <12.0,12.0> <12.0,12.0>
Processing.preProcess(String) <1.0,1.0> <1.0,1.0> <2.0,2.0> <2.0,2.0>
Total <192.0,192.0> <81.0,81.0> <164.0,164.0> <174.0,174.0>
Average <3.6923076923076925,3.6923076923076925> <1.5576923076923077,1.5576923076923077> <3.1538461538461537,3.1538461538461537> <3.3461538461538463,3.3461538461538463>

新增方法的复杂度都不高

image-20240321174306443

代码增量只有不到 100 行,本次作业对我来说相对轻松,之前的架构能很好地完成本次作业迭代

Bug 分析

  • 本次作业中,我在自测时发现了一个 bug

    2
    f(y,x)=y^2
    g(y,x)=f(x,y)
    g(1,5)

    应该输出 25,但我的程序输出了 1。这是因为在自定义函数字符串替换的时候,会把替换后的 uvw 看作是还没有被替换的东西,进行了重复的替换。

    解决方法:把每个形参用不同的值进行存储,不要统一使用 uvw。我的解决方法是用 fu fv fw gu gv…来代替 uvw,从而保证不会有重复替换的情况出现。

  • 在强测中,我成功 hack 了房间里的一名同学

    2
    f(y,x,z)=1
    g(z)=f(1,1,1)
    f(1,1,g(1))

    该同学的程序会抛出异常

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
    at FuncMap.submit0(FuncMap.java:96)
    at FuncMap.submit(FuncMap.java:41)
    at Main.main(Main.java:29)

第一单元作业总结

由于是第一次接触 Java,我的架构设计的并不是很理想,在最开始的一两周不是很理解什么是接口,继承这些关系,也一直不懂为什么同学们的架构中都加入了PolyMono这两个类。直到这周的研讨课,听了同学对自己架构的分享我才理解。我确实认为加入了PolyMono的结构是更合适的,从架构上也更符合自下而上的思想,读写分离使得操作更加方便清晰。

而我的架构的弊端也显而易见

  1. 用看似是 expr term factor 的命名,实际他们可能是以 poly tempPoly Mono 的形式存在的,感觉程序的架构不是很容易表述清楚,很容易让别人误解。

  2. 在 Factor 中没有使用接口,我认为程序的可拓展性是大幅下降的。同时,为了能让数据在 Expr Term Factor 中传输,我多写了很多方法,但如果使用接口就不需要这么麻烦了。

  3. 相比加入了PolyMono的架构而言,我的架构不够清晰,可扩展性也比较低。

如果能再来一次,能不能让我在上个学期就知道有 oop 这门课啊(哭)