此作业要求https://edu.cnblogs.com/campus/nenu/2018fall/homework/2148
HTTP: https://git.coding.net/gongylx/f4.git
功能一:
对于作业四则运算的功能一,最开始分析这个功能时,我和我的队友选择了用我们较为擅长的python进行编写,通过分析老师的spec,总结出框架,要完成的目标是随机生成表达式,在控制台输入答案,后台进行运算与控制台输入的答案进行比较,给出比较的结果,控制表达式数量,用一个变量计算答对题目数目。这里控制台输入的是f4 ,这里通过上次的作业,我学会了通过控制台终端直接把.py文件转换成.exe程序。所以考虑实现上,决定用python 。利用python 里的random.randint()方法随机生成数字和运算符进行情况判断。这时候的代码如下:
def newint(encoding='utf-8'): opr = ['+', '-', '*', '/'] fh1 = random.randint(0, 3) fh2 = random.randint(0, 3) fh3 = random.randint(0, 3) n1 = random.randint(1, 20) n2 = random.randint(1, 20) n3 = random.randint(1, 20) n4 = random.randint(1, 20) rjg = 0 if fh1 == 0: if fh2 == 0: if fh3 == 0: rjg = n1+n2+n3+n4 elif fh3 == 1: rjg = n1+n2+n3-n4 elif fh3 == 2: rjg = n1+n2+n3*n4 elif fh3 == 3: rjg = n1+n2+n3/n4 elif fh2 == 1: if fh3 == 0: rjg = n1+n2-n3+n4 elif fh3 == 1: rjg = n1+n2-n3-n4 elif fh3 == 2: rjg = n1+n2-n3*n4 elif fh3 == 3: rjg = n1+n2-n3/n4 elif fh2 == 2: if fh3 == 0: rjg = n1+n2*n3+n4 elif fh3 == 1: rjg = n1+n2*n3-n4 elif fh3 == 2: rjg = n1+n2*n3*n4 elif fh3 == 3: rjg = n1+n2*n3/n4 elif fh2 == 3: if fh3 == 0: rjg = n1+n2/n3+n4 elif fh3 == 1: rjg = n1+n2/n3-n4 elif fh3 == 2: rjg = n1+n2/n3*n4 elif fh3 == 3: rjg = n1+n2/n3/n4 elif fh1 == 1: if fh2 == 0: if fh3 == 0: rjg = n1-n2+n3+n4 elif fh3 == 1: rjg = n1-n2+n3-n4 elif fh3 == 2: rjg = n1-n2+n3*n4 elif fh3 == 3: rjg = n1-n2+n3/n4 elif fh2 == 1: if fh3 == 0: rjg = n1-n2-n3+n4 elif fh3 == 1: rjg = n1-n2-n3-n4 elif fh3 == 2: rjg = n1-n2-n3*n4 elif fh3 == 3: rjg = n1-n2-n3/n4 elif fh2 == 2: if fh3 == 0: rjg = n1-n2*n3+n4 elif fh3 == 1: rjg = n1-n2*n3-n4 elif fh3 == 2: rjg = n1-n2*n3*n4 elif fh3 == 3: rjg = n1-n2*n3/n4 elif fh2 == 3: if fh3 == 0: rjg = n1-n2/n3+n4 elif fh3 == 1: rjg = n1-n2/n3-n4 elif fh3 == 2: rjg = n1-n2/n3*n4 elif fh3 == 3: rjg = n1-n2/n3/n4 elif fh1 == 2: if fh2 == 0: if fh3 == 0: rjg = n1*n2+n3+n4 elif fh3 == 1: rjg = n1*n2+n3-n4 elif fh3 == 2: rjg = n1*n2+n3*n4 elif fh3 == 3: rjg = n1*n2+n3/n4 elif fh2 == 1: if fh3 == 0: rjg = n1*n2-n3+n4 elif fh3 == 1: rjg = n1*n2-n3-n4 elif fh3 == 2: rjg = n1*n2-n3*n4 elif fh3 == 3: rjg = n1*n2-n3/n4 elif fh2 == 2: if fh3 == 0: rjg = n1*n2*n3+n4 elif fh3 == 1: rjg = n1*n2*n3-n4 elif fh3 == 2: rjg = n1*n2*n3*n4 elif fh3 == 3: rjg = n1*n2*n3/n4 elif fh2 == 3: if fh3 == 0: rjg = n1*n2/n3+n4 elif fh3 == 1: rjg = n1*n2/n3-n4 elif fh3 == 2: rjg = n1*n2/n3*n4 elif fh3 == 3: rjg = n1*n2/n3/n4 elif fh1 == 3: if fh2 == 0: if fh3 == 0: rjg = n1/n2+n3+n4 elif fh3 == 1: rjg = n1/n2+n3-n4 elif fh3 == 2: rjg = n1/n2+n3*n4 elif fh3 == 3: rjg = n1/n2+n3/n4 elif fh2 == 1: if fh3 == 0: rjg = n1/n2-n3+n4 elif fh3 == 1: rjg = n1/n2-n3-n4 elif fh3 == 2: rjg = n1/n2-n3*n4 elif fh3 == 3: rjg = n1/n2-n3/n4 elif fh2 == 2: if fh3 == 0: rjg = n1/n2*n3+n4 elif fh3 == 1: rjg = n1/n2*n3-n4 elif fh3 == 2: rjg = n1/n2*n3*n4 elif fh3 == 3: rjg = n1/n2*n3/n4 elif fh2 == 3: if fh3 == 0: rjg = n1/n2/n3+n4 elif fh3 == 1: rjg = n1/n2/n3-n4 elif fh3 == 2: rjg = n1/n2/n3*n4 elif fh3 == 3: rjg = n1/n2/n3/n4 print(n1, opr[fh1], n2,opr[fh2] ,n3 ,opr[fh3], n4 ,'= ', end='') return rjg
这里实现4个数字和3个运算符的表达式的方法我们俩人都认为比较笨拙,虽然功能实现了,但是代码略显幼稚,这里考虑到用栈、逆波兰式去计算,但是又碍于自己的python编程能力还不会,这时候又考虑到后面的功能2和3,需要加上括号,这时候如果再用列举的方法去实现的话,形式太多,很难实现。这时候选择了更换语言,我们俩商量结果是用老师推荐的c#进行编写,由于本科学习的c#都忘光了,所以我们决定边学边实现,首先我们俩从网上百度用C#实现四则运算的方法,然后我们俩一人选了一个觉得功能比较全的进行剖析学习,互相讲解,这时候发现了一系列的问题。
对于功能一,首先是用Random方法实现数字和运算符的生成。这里运用switch进行判断识别+-*/,这里遇到的难点是老师spec里讲到的不允许出现除不尽的小数,我们百度了好多,最后选择用度娘的一个方法,我们要避免十进制下的无限小数,只需要让被除数的素因子只有2和5,所以我们将分别判断后三个数为被除数的时候,3种情况下,我们将这3个被除数生成为素因子2和5的幂的形式,这样就保证了表达式结果不会出现无限循环的小数,代码如下:
public class Test { public char RandSymbol()//生成运算符 { Random r = new Random(); int rr = r.Next(4); switch (rr) { case 0: return '+'; case 1: return '-'; case 2: return '*'; case 3: return '/'; default: return '0'; } } public int RandNumber()//生成一个0到100的数 { Random rn = new Random(); return rn.Next(13); } public double ansr = 0;//表达式的结果 public int num1, num2, num3, num4;//生成4个数字进行运算 public int n2, m5;//pow(2,n)*pow(5,m) public char op1, op2, op3;//运算符 public int BracketPattern;//增加括号 public char eq = '=';//等号 public char lb = '(';//左括号 public char rb = ')';//右括号 public string ToEval;//表达式的累加 public void GetExp()//获取没有括号的表达式 { num1 = RandNumber(); System.Threading.Thread.Sleep(15); num2 = RandNumber(); System.Threading.Thread.Sleep(15); num3 = RandNumber(); System.Threading.Thread.Sleep(15); num4 = RandNumber(); System.Threading.Thread.Sleep(15); op1 = RandSymbol(); System.Threading.Thread.Sleep(15); op2 = RandSymbol(); System.Threading.Thread.Sleep(15); op3 = RandSymbol(); if (op1 == '/')//如果我们要避免十进制下的无限小数,只需要让被除数的素因子只有2和5,以下同理。 { Random rd = new Random(); n2 = rd.Next(1, 5); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 3); num2 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); } if (op2 == '/') { Random rd = new Random(); n2 = rd.Next(1, 5); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 3); num3 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); } if (op3 == '/') { Random rd = new Random(); n2 = rd.Next(1, 5); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 3); num4 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); } ToEval = num1.ToString() + op1.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString(); GetAnsr(); }
这里为了更好的实现以后的功能,我们采用了后缀表达式和栈的辅助去处理表达式,计算出结果,然后将控制台输入的结果进行比较,得出答案。展示表达式的代码如下:
public void DispExp()//展示表达式 { string Disp = ToEval + eq; Console.WriteLine("{0}", Disp); } public void DispExpAns(Test t) { string Disp = ToEval + eq; if (Math.Abs((double)Math.Round(t.ansr) - t.ansr) < 1e-7) { Console.WriteLine("{0,-20}{1,-7}", Disp, (int)t.ansr); } else { string floatValue = t.ansr.ToString(); floatValue = floatValue.TrimEnd('.', '0'); Console.WriteLine("{0,-20}{1,-7}", Disp, floatValue); } }
计算答案的方式采用调用逆波兰的表达式的方法,去计算逆波兰表达式的值传递给计算答案,代码如下:
public void GetAnsr()//计算答案 { string TE = ToEval; Random rd = new Random(); this.ansr = this.Calucate(TE);//调用计算逆波兰表达式的方法 // Console.WriteLine("ans is {0}", this.ansr); }
计算答案的时候就要考虑到的问题便是利用栈去计算逆波兰表达式,这时候要用到的是运算符的优先级,确保表达式是按照规定优先级进行运算的,代码如下:
static bool IsSize(string s)//是运算符 { string ts = "+-*/%^"; return ts.IndexOf(s) > -1; } Dictionary<char, int> priorities = null;//优先级 const string operators = "+-*/%^"; public void opinit()//初始化优先级 { priorities = new Dictionary<char, int>(); priorities.Add('#', -1); priorities.Add('+', 0); priorities.Add('-', 0); priorities.Add('*', 1); priorities.Add('/', 1); priorities.Add('%', 1); priorities.Add('^', 2); }
具体的利用转逆波兰的方式去计算答案的代码如下:
double Compute(double leftNum, double rightNum, char op)//计算答案 { switch (op) { case '+': return leftNum + rightNum; case '-': return leftNum - rightNum; case '*': return leftNum * rightNum; case '/': return leftNum / rightNum; case '%': return leftNum % rightNum; case '^': return Math.Pow(leftNum, rightNum); default: return 0; } } bool IsOperator(char op) { return operators.IndexOf(op) > -1; } bool IsLeftAssoc(char op) { return op == '+' || op == '-' || op == '*' || op == '/' || op == '%'; } Queue<object> PreOrderToPostOrder(string expression)//转逆波兰表达式 { var result = new Queue<object>(); var operatorStack = new Stack<char>(); operatorStack.Push('#'); char top, cur, tempChar; string tempNum; if (expression[0] == '-') expression = '0' + expression; for (int i = 0, j; i < expression.Length;) { cur = expression[i++]; top = operatorStack.Peek(); if (cur == '(') { operatorStack.Push(cur); } else { if (IsOperator(cur)) { while (IsOperator(top) && ((IsLeftAssoc(cur) && priorities[cur] <= priorities[top])) || (!IsLeftAssoc(cur) && priorities[cur] < priorities[top])) { result.Enqueue(operatorStack.Pop()); top = operatorStack.Peek(); } operatorStack.Push(cur); } else if (cur == ')') { while (operatorStack.Count > 0 && (tempChar = operatorStack.Pop()) != '(') { result.Enqueue(tempChar); } } else { tempNum = "" + cur; j = i; while (j < expression.Length && (expression[j] == '.' || (expression[j] >= '0' && expression[j] <= '9'))) { tempNum += expression[j++]; } i = j; result.Enqueue(tempNum); } } } while (operatorStack.Count > 0) { cur = operatorStack.Pop(); if (cur == '#') continue; if (operatorStack.Count > 0) { top = operatorStack.Peek(); } result.Enqueue(cur); } return result; } public double Calucate(string expression)//计算表达式的值 { try { var rpn = PreOrderToPostOrder(expression); var operandStack = new Stack<double>(); double left, right; object cur; while (rpn.Count > 0) { cur = rpn.Dequeue(); if (cur is char) { right = operandStack.Pop(); left = operandStack.Pop(); operandStack.Push(Compute(left, right, (char)cur)); } else { operandStack.Push(double.Parse(cur.ToString())); } } return operandStack.Pop(); } catch { throw new Exception("表达式格式不正确!"); } } }
主函数里判断控制台输入的是否有-c ,如果没有-c,则实现的便是功能一,这时候通过判断计算答案和表达式结果的比较,这里利用两数相减结果在小数点后7位内相等则判定正确。具体的主函数代码如下:
static void Main(string[] args) { int num;//输入表达式中的数字 int cnt = 0; int token = 0; var arguments = CommandLineArgumentParser.Parse(args);//命令行参数 int anslen = 1;//用来作为表达式的结果 double[] ansrep;//排列存储结果 ansrep = new double[1000]; ansrep[0] = -23579; if (!arguments.Has("-c"))//如果命令行参数没有-c就输出20个算式 num = 20; else { num = int.Parse(arguments.Get("-c").Next);//命令行参数中得到要输出的表达式数量 if (num <= 0) { throw new Exception("题目数量必须为 正整数!"); } token = 1; } if (token == 0) { for (int i = 0; i < num; i++) { Test t = new Test();//new Test t.opinit(); t.GetBracketExp(); // t.GetExp(); //t.NoRepeatedAns(anslen, ansrep); ansrep[(anslen++) - 1] = t.ansr; t.DispExp();//显示表达式 Console.Write("?");//控制台显示 double ans = double.Parse(Console.ReadLine()); // Console.WriteLine("{0},{1}",ans,t.ansr); if (Math.Abs(ans - t.ansr) < 1e-7)//答案正确 { Console.WriteLine("答对啦,你真是个天才!"); cnt++; } else//答案错误 { if (Math.Abs((double)Math.Round(t.ansr) - t.ansr) < 1e-7) { Console.WriteLine("再想想吧,答案似乎是{0}喔! ", (int)t.ansr); } else//十进制 { string floatValue = t.ansr.ToString(); floatValue = floatValue.TrimEnd('.', '0'); Console.WriteLine("再想想吧,答案似乎是{0}喔!", floatValue); } } } Console.WriteLine("你一共答对{0}道题,共20道题。", cnt); } else//实现打印 { for (int i = 0; i < num; i++) { Test t = new Test();//new Test t.opinit(); t.GetBracketExp(); ansrep[(anslen++) - 1] = t.ansr; t.DispExpAns(t);//展示表达式和答案 } } }
这里功能一的实现在控制台直接输入程序名字,然后自动生成默认的20道题,回答正确得到回复,错误得到回复然后告诉正确答案,最后给出答对题目的数量和题目总数量。功能实现如下图所示:
这里默认的20道题结束时,给出总结,如下图:
功能二:
这里功能二的实现是在功能一的基础上实现括号的加入,这里最难的就是当时考虑到括号的加入到底应该如何判断情况,这里我们考虑到的第一种方法是递归的方法,将表达式进行分解,遇到括号的时候先计算括号里面的,然后将结果值存入变量再进行运算。第二种方法便是老师提到的利用栈和逆波兰式进行计算,将所有的表达式入栈,然后利用入栈出栈将相邻最近的两数进行运算,得出总的表达式的值,和计算结果进行比较。
这里最难的地方是括号情况的判断,4个数字和3个运算符,括号位置一共有9种情况,这里同样的要对被除数进行处理,保证答案不会有无限循环的小数,功能实现图与功能一实现图相同,具体代码如下:
public void GetBracketExp()//获取有括号的表达式 { num1 = RandNumber(); System.Threading.Thread.Sleep(15); num2 = RandNumber(); System.Threading.Thread.Sleep(15); num3 = RandNumber(); System.Threading.Thread.Sleep(15); num4 = RandNumber(); System.Threading.Thread.Sleep(15); op1 = RandSymbol(); System.Threading.Thread.Sleep(15); op2 = RandSymbol(); System.Threading.Thread.Sleep(15); op3 = RandSymbol(); Random rdm = new Random(); int brkp = rdm.Next(11);//括号存在的方式 if (brkp != 0)//brkp为0时不是包含括号的表达式 { Random rd = new Random(); n2 = rd.Next(1, 3); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 2); num2 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); n2 = rd.Next(1, 3); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 2); num3 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); n2 = rd.Next(1, 3); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 2); num4 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); num1 = num2 * num3 * num4; } else { if (op1 == '/') { Random rd = new Random(); n2 = rd.Next(1, 3); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 2); num2 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); } if (op2 == '/') { Random rd = new Random(); n2 = rd.Next(1, 3); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 2); num3 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); } if (op3 == '/') { Random rd = new Random(); n2 = rd.Next(1, 3); System.Threading.Thread.Sleep(15); m5 = rd.Next(1, 2); num4 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5)); } } switch (brkp) { case 0: ToEval = num1.ToString() + op1.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString(); break; case 1: ToEval = lb.ToString() + num1.ToString() + op1.ToString() + num2.ToString() + rb.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString(); break; case 2: ToEval = lb.ToString() + num1.ToString() + op1.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + op3.ToString() + num4.ToString(); break; case 3: ToEval = lb.ToString() + lb.ToString() + num1.ToString() + op1.ToString() + num2.ToString() + rb.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + op3.ToString() + num4.ToString(); break; case 4: ToEval = lb.ToString() + num1.ToString() + op1.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + rb.ToString() + op3.ToString() + num4.ToString(); break; case 5: ToEval = num1.ToString() + op1.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + op3.ToString() + num4.ToString(); break; case 6: ToEval = num1.ToString() + op1.ToString() + lb.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + op3.ToString() + num4.ToString() + rb.ToString(); break; case 7: ToEval = num1.ToString() + op1.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString() + rb.ToString(); break; case 8: ToEval = num1.ToString() + op1.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + lb.ToString() + num3.ToString() + op3.ToString() + num4.ToString() + rb.ToString() + rb.ToString(); break; case 9: ToEval = lb.ToString() + num1.ToString() + op1.ToString() + num2.ToString() + rb.ToString() + op2.ToString() + lb.ToString() + num3.ToString() + op3.ToString() + num4.ToString() + rb.ToString(); break; default: ToEval = num1.ToString() + op1.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString(); break; } GetAnsr(); }
功能三:
功能三是要在控制台输入-c X,这里的spec要求是将控制台参数作为生成题目数量,这里的难点就是main函数中的情况判断,命令行参数获取类的代码如下:
public class CommandLineArgument//命令行参数获取类 { List<CommandLineArgument> _arguments; int _index; string _argumentText; public CommandLineArgument Next { get { if (_index < _arguments.Count - 1) { return _arguments[_index + 1]; } return null; } } public CommandLineArgument Previous { get { if (_index > 0) { return _arguments[_index - 1]; } return null; } } internal CommandLineArgument(List<CommandLineArgument> args, int index, string argument) { _arguments = args; _index = index; _argumentText = argument; } public CommandLineArgument Take() { return Next; } public IEnumerable<CommandLineArgument> Take(int count) { var list = new List<CommandLineArgument>(); var parent = this; for (int i = 0; i < count; i++) { var next = parent.Next; if (next == null) break; list.Add(next); parent = next; } return list; } public static implicit operator string(CommandLineArgument argument) { return argument._argumentText; } public override string ToString() { return _argumentText; } } public class CommandLineArgumentParser//命令行参数解析器 { List<CommandLineArgument> _arguments; public static CommandLineArgumentParser Parse(string[] args) { return new CommandLineArgumentParser(args); } public CommandLineArgumentParser(string[] args) { _arguments = new List<CommandLineArgument>(); for (int i = 0; i < args.Length; i++) { _arguments.Add(new CommandLineArgument(_arguments, i, args[i])); } } public CommandLineArgument Get(string argumentName) { return _arguments.FirstOrDefault(p => p == argumentName); } public bool Has(string argumentName) { return _arguments.Count(p => p == argumentName) > 0; } } }
功能实现图:
对于结对编程的体会:
我觉得结对编程确实具有非常重要的意义,一个人编写代码,总是有种灯下黑的现象。可能你自己犯的很微小的错误,你花了大把大把的时间,还是搞不出来。而另一个人只需要看一下就能指出,这提高了复审效率。可以不断从别人那里学习,提高自己的水平。这次结对编程,我从朱池苇大佬那里学到了很多,比如良好的代码风格,清晰的编码思路,以及熟练的调试技巧等。通过两个人的讨论,更好的解决问题等。我们两个是属于熟悉的编程语言不一致的队伍,这给我们带来了很多的困难,但是既然选择了结成队友,就要克服困难,我们通过尝试,改变了语言,虽然浪费了时间,但是真的学到了很多东西,从对方的编程习惯上学到了很多自己之前不会的东西,比如编代码前先建立完整的框架,我之前都是简单的思考下框架就行了,这次的作业,我们从网上、学长学姐那儿学到了很多之前不会的东西,两个人结对,我们在学习的过程中互相讲授自己理解的地方,加快了理解的进度和程度。
在结对编程中的争论,复审和收获:
(1)争论点是对于编程语言的选择,因为我们俩所熟悉的编程语言不同,我比较擅长用python,而她擅长java,所以这时候我们选择用各自语言对于本作业的适合程度说服对方,这时候我们列出了三种处理方式,要不我就学java,要不她就学python,要不我们俩学c#,因为上次作业大多数同学都用了python,这样功能测试的时候更方便,所以我们开始决定用python 去写,但是功能一实现之后出现了问题,代码过于繁琐,所以我们决定学习C#,最终决定了编码语言。
(2)争论点是对于如何处理有答案是无限循环小数的情况(即除不尽的情况),我们开始商量的结果是不让被除数为3,后来想到只是不为3还不行,例如13也会有这种情况,这时候我们遇到了困难,达到了所学知识的瓶颈,然后我们通过咨询学长,百度,pull别人的代码分析,最终看到了这个解决方法,将被除数设定为素因子只含2和5的数,这时候避免了bug的出现。
(3)争论点是对于功能实现是使用递归方法还是逆波兰和栈实现,首先要明确的是两种方法也是在百度搜索的,我们对于两种方法都不太熟悉,这时候需要决定一种,她觉得递归在数据结构中刚学完,看到百度上解释的用递归方法实现上比较简单,但是我坚持用栈也逆波兰,原因之一是这是老师的建议,之所以老师建议使用这种方法,肯定有原因,或是因为这个功能很重要,或是因为这个方法比较简单,所以我想用栈和逆波兰实现。最终因为我的坚持我们决定了使用后者方法实现功能。
(4)感悟一是对于结对编程的优点:
1. 在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。
2. 对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感,同时,能够降低学习成本,一边编程,一边共享知识和经验,有效地在实践中进行学习。
3. 在心理上, 当有另一个人在你身边和你紧密配合, 做同样一件事情的时候, 你不好意思开小差, 也不好意思糊弄。
4. 在企业管理层次上,结对能更有效地交流,相互学习和传递经验,能更好地处理人员流动。因为一个人的知识已经被其他人共享。
(5)感悟二是对于结对编程的缺点:
1.对于有不同习惯的编程人员,可以在一起工作会产生麻烦,甚至矛盾。
2.程序员们有时会对一个问题各执己见,导致浪费很多时间彼此争论。
3.两个人在一起工作可能会出现工作精力不能集中的情况。程序员可能会交谈一些与工作无关的事情,反而分散注意力,导致效率比单人更为低下。
4.有经验的人更喜欢单兵找个人来站在他背后看着他可能会让他感到非常的不爽,最终导致编程时受到情绪影响,反而出现反作用。
工作地点:东北师范大学净月二食堂一楼