git http地址: https://git.coding.net/clairewyd/f4.git
SSH地址:git@git.coding.net:clairewyd/f4.git
要求1 参考《构建之法》第4章两人合作,结对编程上述功能,要求每人发布随笔1篇 (代码是共同完成的,博客是分别完成的)。 (1) 给出每个功能的重点、难点、编程收获。(2)给出结对编程的体会,以及 (3) 至少5项在编码、争论、复审等活动中花费时间较长,给你较大收获的事件。 (10分)
功能1 的主要实现过程:
定义Question类实现功能1 的主要功能,该类中定义numStack,和operatorStack两个Stack类型的类成员变量分别用来存放产生的随机数学运算式的数字,运算符及最后产生的运算式结果。首先产生数学表达式,在TheFinal方法中进行调用GetStack方法运算并判断它是否是符合条件的运算式,如果是则输出在控制台,之后进行下一步操作,否则重新生成表达式。
主要函数:
用于计算数学表达式结果GetStack(char[] stackArr)。形参是一个字符数组,如果是数字则加入数字栈,如果是“+”或者“-”则判断符号栈栈顶元素,如果栈顶元素是四则运算符号则进行退栈计算操作,将中间结果加入数字栈,否则直接将符号加入符号栈。如果是“*”,“/”则判断符号栈栈顶元素,如果为“*”或者“/”,则进行退栈计算。遍历完之后,如果此时符号栈不为空,则继续调用退栈函数进行计算,最后数字栈栈顶元素即为表达式的结果。
/// <summary> /// 进行堆栈操作,最后numstack的栈顶元素为结果 /// </summary> /// <param name="stackArr"></param> public void GetStack(char[] stackArr) { for (int i = 0; i < stackArr.Length; i++) { if (stackArr[i] - '0' >= 0 && stackArr[i] - '0' <= 9) { double num = double.Parse(stackArr[i].ToString()); NumStack.Push(num); } else { if (OperatorStack.Count == 0) { OperatorStack.Push(stackArr[i]); } else { if (stackArr[i] == '+' || stackArr[i] == '-') { char oper = (char)OperatorStack.Peek(); if (oper == '+' || oper == '-' || oper == '*' || oper == '/') { //退栈函数,计算中间结果并将相应数字栈和符号栈进行退栈操作 TempResult(NumStack, OperatorStack); OperatorStack.Push(stackArr[i]); } else { OperatorStack.Push(stackArr[i]); } } else if (stackArr[i] == '*' || stackArr[i] == '/') { char oper = (char)OperatorStack.Peek(); if (oper == '*' || oper == '/') { TempResult(NumStack, OperatorStack); OperatorStack.Push(stackArr[i]); } else { OperatorStack.Push(stackArr[i]); } } } } } while (OperatorStack.Count != 0) { TempResult(NumStack, OperatorStack); } }
功能2:
功能2部分代码在QuestionBracket类中实现,该类直接继承自功能1部分的Question类,重载了GetStack方法,加入计算括号的功能。当操作符是”(“时直接加入符号栈,当是”)“时则调用TempResul函数直至")"出栈为止。
/// <summary> /// 进行堆栈操作,最后numstack的栈顶元素为结果 /// </summary> /// <param name="stackArr">参加运算的字符数组</param> new public void GetStack(char[] stackArr) { for (int i = 0; i < stackArr.Length; i++) { if (stackArr[i] - '0' >= 0 && stackArr[i] - '0' <= 9) { double num = double.Parse(stackArr[i].ToString()); NumStack.Push(num); } else { if (OperatorStack.Count == 0 || stackArr[i] == '(') { OperatorStack.Push(stackArr[i]); } else { if (stackArr[i] == '+' || stackArr[i] == '-') { char oper = (char)OperatorStack.Peek(); if (oper == '+' || oper == '-' || oper == '*' || oper == '/') { TempResult(NumStack, OperatorStack); OperatorStack.Push(stackArr[i]); } else { OperatorStack.Push(stackArr[i]); } } else if (stackArr[i] == '*' || stackArr[i] == '/') { char oper = (char)OperatorStack.Peek(); if (oper == '*' || oper == '/') { base.TempResult(NumStack, OperatorStack); OperatorStack.Push(stackArr[i]); } else { OperatorStack.Push(stackArr[i]); } } else if (stackArr[i] == ')') { while (((char)base.OperatorStack.Peek()) != '(') { TempResult(base.NumStack, base.OperatorStack); } base.OperatorStack.Pop(); } } } } while (OperatorStack.Count != 0) { TempResult(NumStack, OperatorStack); } }
功能3 :功能3和功能2 均在QuestionBracket类中,该功能主要使用了字符串的格式化,及文件的写入。
/// <summary> /// 功能3写入文件 /// </summary> public void SaveFile() { string path = "question.txt"; StreamWriter streamWriter = new StreamWriter(path, true); string question = this.TheFinal(); //进行格式化写入 streamWriter.Write(string.Format("{0,-50}", question)); //获取计算结果并写入 streamWriter.Write((double)base.NumStack.Peek()); streamWriter.WriteLine(); Console.WriteLine(string.Format("{0,-50}", question) + (double)base.NumStack.Peek()); streamWriter.Flush(); streamWriter.Close(); }
功能4实现在参考了资料后只能实现两个分数的加减乘除,结果约分后以带分数的形式输出,但是因为前几部分的堆栈存储结构问题使实现完整功能四要求有困难。
以下是实现分数约分,拼接功能的函数:
private static string Convert(int fz, int fm) { if (fz == 0) return "0"; if (fm == 0) { return "Inf"; } StringBuilder result = new StringBuilder(); Boolean flag = false; int k = 0; if (fz < 0) { result.Append("(-"); fz = -fz; flag = true; } k = fz / fm; fz = fz % fm; if (fz == 0) { if (k != 0) result.Append(k); if (!flag) return result.ToString(); else return result.Append(")").ToString(); } int gcd = Gcd(fz, fm); if (gcd != 1) { fz /= gcd; fm /= gcd; } if (k != 0) result.Append(k).Append(" "); result.Append(fz).Append("/").Append(fm); if (flag) result.Append(")"); return result.ToString(); }
功能4 完成部分
1 在代码规范编写过程中,由于两人的编码风格不同,产生过分歧。代码规则中有一条单行注释放在代码行上方,但是两人中有一人习惯放在右侧,所以讨论了很久。
2 对于代码的逻辑结构也产生过分歧,当时讨论了两种实现方法,一种是使用接口,让各个功能的工具类均实现这一接口,一种是现在程序所采用的以功能一实现类Question为父类,其他功能继承Question类。采用这一结构是因为这样实现更有逻辑性,而且只需重写一部分函数,代码可读性更好,更加简洁。
3 代码复审时由于代码规范不够严谨(关键语句需要加注释),由于对“关键”一词有分歧,所以找了室友王静茹进行代码阅读,除原本有注释的代码行,对于她有疑问的代码就加入代码注释。
4 编码时用于产生最后输出运算式的theFinal方法,在产生的运算式不符合要求要产生新的运算式时,由于忘记清空Numstack栈,会产生异常,排查了很久,才找到原因。
5 单元测试中GetStack函数中有很多分支结构,为了能够完成所有的条件覆盖,所以设计测试用例花费了一些时间。
要求2 给出照片1张,包括结对的2位同学、工作地点、计算机,可选项包括其他能表达结对编程工作经历的物品或场景。 (5分)