导语:
本次的总结,我打算这么写:UML图、回忆、收获。虽然想的很好,但是因为老夫连挂了后两次作业,尤其是第三次写的和狗啃的一样。所以第三次的内容,我可能重点会主要放在读别人的代码上,毕竟没吃过猪肉,但还是可以见见猪跑的。
正文:
第一次作业:
具体思路,就是先将输入的字符串进行一定程度的处理(比如:去掉空格、合并正负号),然后通过正则表达式:"([+-])((\\d+)\\*)?x(\\*{2}([+-]?\\d+))?"
对字符串的各个项进行判断,进行处理。具体代码如下:
static final String polyRegex =
"([+-])((\\d+)\\*)?x(\\*{2}([+-]?\\d+))?";
public String parseStr(String inputStr) {
String string = this.processStr(inputStr);
Pattern pattern = Pattern.compile(polyRegex);
Matcher matcher =
pattern.matcher(string);
while (matcher.find()) {
String operatorStr =
matcher.group(1);
String coefStr = matcher.group(3);
String indexStr = matcher.group(5);
BigInteger coef;
BigInteger index;
if (operatorStr.equals("+")) {
//coef =
Integer.getInteger(coefStr);
if (null == coefStr) {
coef = new BigInteger("1");
}
else {
//coef =
Integer.getInteger(coefStr);
//coef =
Integer.valueOf(coefStr);
coef = new BigInteger(coefStr);
}
}
else {
if (null == coefStr) {
//coef = -1;
coef = new BigInteger("-1");
}
else {
//coef = -
Integer.getInteger(coefStr);
//coef = -
Integer.valueOf(coefStr);
coef = new BigInteger(coefStr).negate();
}
}
if (null == indexStr) {
//index = 1;
index = new BigInteger("1");
}
else {
//index =
Integer.getInteger(indexStr);
//index =
Integer.valueOf(indexStr);
index = new BigInteger(indexStr);
}
//poly.addTerm(coef,
index);
HashMap<BigInteger,
BigInteger> map = poly.getTerms();
if (map.containsKey(index))
{
BigInteger originalCoef =
map.get(index);
//map.put(index, coef
+ originalCoef);
map.put(index,
coef.add(originalCoef));
}
else {
map.put(index, coef);
}
}
return string;
}
可以看得出parseStr()写的很凌乱,这个方法做的功能设定的时候不清晰,换句话说层次设计的不好。
首先,指数、系数干的话罗列在一起,很乱;而且指数的判断严格和系数的判断挂钩,耦合严重。导致我在进行课下测试的时候,很多bug都和这里有关。
其次,我们可以很容易看得出来,在抽离指数、系数过程中,过多的if、else语句来判断特殊格式的问题,导致逻辑结构混乱,混乱就容易出bug。
应当怎样解决呢,我这里的想法进攻抛砖引玉。可以设计一个这样的方法standardizeStr()对输入的字符串进行标准化,将每一项都变成标准的:
[符号](系数)*x**[符号](指数)
通过标准化,可以极大地减少指数、系数特殊判断的问题。
这也是我在第二次作业中实现的思路。
第二次作业:
与上一次作业相比,这一次增加了一个TerneryIndex类,即三元指数,但是本质上和上一次没有区别。
首先标准化,将每一项都化为如下的形式:
a*x**b*sin(x)**c*cos(x)**d
这一步涉及了合并因子指数,最终分别提取x\sin(x)\cos(x)的指数作为三元指数对,以此作为上一次作业中hashmap的键值。作为上一次的迭代,从而重用之前的代码。
我们来看看这个方法怎么样。从我个人的角度出发,现在想想,这种做法其实蠢得可以。最致命的问题就是没有迭代空间。如果将来指导书出了tan(x),根据这个思路,我们还得给标准项加上tan(x),然后正则表达式的捕获组也需要进行修改,hashmap的键也要改,然后输出的时候要考虑的特殊情况更多、更复杂(写完第二次作业,我就觉得下一次作业必然要重构)。
其次就是性能堪忧,因为自己给自己找活干,做了大量不必要的工作,当然现阶段只是多了sin(x), cos(x)的工作,还能跑起来,但是这不是一个可以继续迭代的方案。
说完TerneryIndex,我们来看看判断WRONG FORMAT!的问题。代码如下:
static final String constant = "([+-]?\\d+)";
static final String index = "(\\*{2}" + constant + ")";
static final String trigonometric = "(((sin)|(cos))\\(x\\)" + "(" + index + ")?)";
static final String power = "(x" + "(" + index + ")?)";
static final String factor = "(" + constant + "|" + power + "|" + trigonometric + ")";
static final String term = "([+-]?" + factor + "(\\*" + factor + ")*)";
static final String inputForm = "^([+-]?)" + term + "(([+-]" + term + ")*)$";
public boolean inputFormJudge(String inputStr) {
if (null == inputStr) {
return false;
}
String string = inputStr.replaceAll("[ \t]", "");
Pattern pattern = Pattern.compile(inputForm);
Matcher matcher = pattern.matcher(string);
return matcher.find();
}
好嘛,用一个大正则来判断输入的对不对,会有什么问题?
首先,极其非常特别容易栈溢出。这一次控制了输入量,所以侥幸没有栈溢出。
其次,加了这一步,个人认为这是在浪费性能。纵观整个程序,我们用正则遍历了输入的字符串两次,一次判断、一次处理。
所以我个人提出的解决方法是这样的:
每一个因子进行判断、并处理,然后在原字符串中删掉该因子。处理完了,判断处理后的原字符串是否为空字符串,是就return true,否则就输出WF,然后return false。