382
社区成员
本代码架构如下图所示:
本代码与training的代码的核心思路相同,都是采用递归下降的方式,并在此基础上添加了一些内容:
笔者设计了一个Function
类,其中存储了函数的名称,函数的形参,以及函数的形参表达式,即存储了函数的具体信息,这样在将表达式中的函数替换时更加方便。
本人设计了一个Process
类,其中的move()
函数里采用正则表达式的方法对表达式进行了化简,例如去除连续的+,-
,将**
暂时变为^
,去除*
后的带符号的整数因子的符号等,都是为了方便之后的对表达式的处理。
本人将待求导的表达式看作一个新的表达式对其进行处理,并在Expr
和Term
类里增添了新的函数来处理求导。
Factor
接口增添新的类Pow
:该类存储三角函数和幂函数本身以及次幂,通过第一个字母是s,c
还是x,y,z
来判断其是三角函数还是幂函数。
本代码设计了较多的类,便于理解和维护;并且有效地使用了正则表达式,大大简化了后面对表达式的处理。
随着hw_1至hw_3的任务的添加,本代码的条理性逐渐降低,使得“面向对象”逐渐有点“面向编程”;没有将三角函数和幂函数存储在两个类里,增大了处理的复杂性。
例如如下输入:
1
f(x,y)=x**2+y
f(y,x)
原来代码的变量代换是依次代换,即按顺序将形参替换为实参,但上述情况就会出现问题,将第一个形参x
换为实参y
后,f
的表达式变成y**2+y
,再将第二个形参y
换为实参x
后,f
的表达式变成x**2+x
,这与期望的结果:y**2+x
不同,原因是所有参数替换不能“同时”完成,导致后面的实参错误地替换掉了前面的实参。
代码是按语句依次执行的,不能同时执行多个语句,因此我们将Function
类中的形参变量不记为x,y,z
,而是记为大写的X,Y,Z
,并且将其中的形参表达式中的所有x,y,z
也替换为X,Y,Z
,这样以上述输入为例,f
的表达式是X**2+Y
,第一次代换后,f
的表达式变成y**2+Y
,第二次代换后,f
的表达式变成y**2+x
,就得到了我们想要的结果。
原来代码对于连续的+,-
是在Process
类的move()
函数里,代码如下:
String symbol1 = "(\+|-){2,}";
Pattern pattern1 = Pattern.compile(symbol1);
Matcher matcher1 = pattern1.matcher(str);
while (matcher1.find()) {
str = str.replaceAll("\+\+", "+");
str = str.replaceAll("\+-", "-");
str = str.replaceAll("-\+", "-");
str = str.replaceAll("--", "+");
}
即按照“同正异负”的原理将连续的+,-
变为单个的+
或-
,然而当遇到连续三个及以上+,-
时,该while
只循环了一次,导致没有变为单个的+
或-
,从而产生错误,原因是一轮循环后没有使用新的str
。
在while
的最后添加语句:
matcher1 = pattern1.matcher(str);
这样在每次的循环最后就会检查新的str
,就成功解决了上述问题。
##三、心得体会纯纯坐牢 在第一单元的这三次作业中,笔者体会到了“面向对象”与“面向编程”的不同,逐渐感受到了java语言中“对象是类的一个实例”的特点,也感悟到了递归下降的方法的优点:与逆波兰表达式方法不同,该方法逐层解析表达式,易于读懂和维护代码,具有数学上的美观性。
体会到了“面向对象”与“面向编程”的不同
————是什么不同啊