Coding 地址:https://git.coding.net/jiapwy/newfouroperation.git
队友:周紫伊
队友博客地址:
一、写在前面
其实这次作业对我而言难度很大,本人花费了很大的功夫才基本实现功能,所以十分感谢我的队友在这次结对编程中对我的帮助,通过这次作业,深深地意识到了自己的不足,希望接下来能再接再厉,争取学到更多知识和技能。
二、PSP
PSP |
任务内容 |
计划时间(min) |
完成时间(min) |
Planning |
计划 |
30 |
20 |
Estimate |
估计这个任务需要多少时间,并规划大致工作步骤 |
30 |
50 |
Development |
开发 |
1100 |
2900 |
Analysis |
需求分析 |
60*5 |
40 |
Design Spec |
生成文档 |
30 |
30 |
Design Review |
设计复审 |
10 |
2 |
Coding Standard |
代码规范 |
5 |
20 |
Design |
具体设计 |
60 |
60 |
Coding |
具体编码 |
600 |
1200 |
Code Review |
代码复审 |
20 |
20 |
Test |
测试 |
30 |
1200 |
Reporting |
报告 |
40 |
180 |
Test Report |
测试报告 |
30 |
120 |
Size Measurement |
计算工作量 |
10 |
25 |
Postmortem& ProcessImprovement Plan |
事后总结, 并提出过程改进计划 |
5*60 |
4*60 |
三、接口的设计
对于面向对象的程序设计而言,信息隐藏是一种重要的软件开发手段,它与对象的封装(encapsulation)与模块化(modularity)密切相关。在我看来,信息隐藏使得一个类把复杂的、敏感的、一旦被外界捕获可能会引起不良后果的内容封装在自身内部,这个类以外的代码得不到此类信息(通过反射等手段可能对得到),以提高程序的安全性与健壮性。
而要设计接口,就要从最根本上进行了解,下面即是一些基本概念:
Interface Design是面向接口编程是软件工程领域常用的设计手段
Loose Coupling是基于面向接口编程,松耦合度是接口设计的目的,接口设计是松耦合度的实现手段
nformation Hiding是信息隐藏指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。
在了解过这些后,我们便可以进行更顺畅的接口设计。
关于interface design与loose coupling
查阅了很多资料,也看了很多同学博客中的分享,我非常同意‘这两个概念是相辅相成的,后者是前者的目的,前者是后者的实现手段。’这句话。
面向接口编程是软件工程领域常用的设计手段,我们在这次结对编程中也不例外,一开始其实并不是很懂得其中的妙处,在不断的尝试中终于领悟到了一点道理。
面向接口的程序设计思想是一种十分有效的手段。做一个项目,只要通过面向于数据组提供的一整套接口进行编程,同时,很多其他工作可以并行进行,这样,不需要等待一个模块的完成就可以预先“使用”这个模块,极大提高了编程的效率和速度。
四、计算模块接口的设计与实现功能
在经过小组的商讨之后,我们的计算模块接口由两个类组成
Main类:模块的主类,负责接收命令行的参数并启动程序以及调用函数
test类:生成符合命令行参数要求的题目,包括加减乘除等运算
计算类中的方法有:
num方法:产生随机数,并且产生要求的算式
calculator方法:负责筛选运算过程中符合要求的式子,并计算正确答案
nibolan方法:中缀表达式转后追表达式 。
五、计算机接口部分的性能改进
见下图
六、计算模块部分单元测试展示
测试输入是有错误的
测试分母为0
代码覆盖率
七、计算模块部分异常处理说明
我们共设计了四种异常处理,分别是出题数量异常处理,数值左边界异常处理,数值右边界异常处理和运算符数量异常处理。
(1)出题数量异常处理
当用户输入的出题数量的数值不在范围内时,提醒用户当前输入的数值不合法,要求用户重新输入。
try { n1 = Integer.parseInt(n.getText()); if (n1 <= 0 || n1 > 10000) { n.setText("请输入合法参数"); return; } flag0 = 1; } catch (Exception a) { n.setText("格式不正确,请重新填写!"); }
(2)数值左边界异常处理
当用户输入的出题数值左边界不在范围内时,提醒用户当前输入的数值不合法,要求用户重新输入。
try { m11 = Integer.parseInt(m1.getText()); if (m11 <= 0 || m11 > 100) { m1.setText("请输入合法参数"); return; } flag1 = 1; } catch (Exception a) { m1.setText("格式不合法,请重新填写!"); }
(3)数值右边界异常处理
当用户输入的出题数值右边界不在[50,1000]范围内时,提醒用户当前输入的数值不合法,要求用户重新输入。
代码展示:
try { m22 = Integer.parseInt(m2.getText()); if (m22 < 50 || m22 > 1000) { m2.setText("请输入合法参数"); return; } flag2 = 1; } catch (Exception a) { m2.setText("格式不合法,请重新填写!"); }
(4)运算符数量异常处理
当用户输入的运算符数量不在范围内时,提醒用户当前输入的数值不合法,要求用户重新输入。
try { o1 = Integer.parseInt(o.getText()); if (o1 <= 0 || o1 > 10) { o.setText("请输入合法参数"); return; } flag3 = 1; } catch (Exception a) { o.setText("格式不合法,请重新填写!"); }
八、界面模块的详细设计过程
(1)欢迎界面
在开始时,我们对GUI的理解十分少,对基本的语句功能实现都非常困难,例如GUI的Button事件都不能实现,设计也十分不美观,下面是最开始的失败界面。
在尝试了很多之后,通过不断的学习,我们改进了界面,终于做的可以看了,并且实现了一部分功能,下面附上代码和图片。
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; public class Main { public static JTextField jtf =new JTextField(5); //文本框 public Main() { JMenuBar jmb=new JMenuBar(); //菜单栏 JFrame jf=new JFrame(); //窗口 final JLabel jlb =new JLabel(); //标签 final JButton jb =new JButton(); //按钮 JPanel jp =new JPanel(); //容器 JPanel jp1 =new JPanel(); jlb.setText("出题数量"); jtf.getText(); jb.setText("生成题目 "); jf.setLayout(new BorderLayout()); //布局 jf.setSize(500, 400); jf.setTitle("欢迎使用四则运算界面"); JMenu jm=new JMenu("语言选择"); //菜单 JMenuItem mi1=new JMenuItem("中文"); //菜单项 JMenuItem mi2=new JMenuItem(""); JMenuItem mi3=new JMenuItem("英文"); //实现选择语言功能 jm.add(mi1); jm.add(mi2); jm.add(mi3); jmb.add(jm); jp.add(jlb); jp.add(jtf); jp1.add(jb); ImageIcon img = new ImageIcon("src/test2/2PAA~5DRU_W_ZJG]3"); jf.add(jp,BorderLayout.NORTH); jf.add(jp1,BorderLayout.CENTER); jf.setJMenuBar(jmb); jf.setVisible(true); mi1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jlb.setText("出题数量"); jtf.getText(); jb.setText("生成题目"); } }); mi2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jlb.setText("出题数量"); jtf.getText(); jb.setText("go"); } }); mi3.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jlb.setText("please input the number of questions you want"); jtf.getText(); jb.setText("generate tests"); //完成英文版 } }); jb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { methodjb(); } }); } //完成最初界面 public static void methodjb(){ new MainFrame(Integer.parseInt(jtf.getText())); } public static void main(String args[]) { new Main(); //主函数调用 } }
(2)答题页面
当填写完出题数量后,再点击生成题目时,会出现另一个界面,页面包括所有生成的题目,以及结果的输入处,包括计时功能的完成,而语言选择项仍然存在,最后是生成题目按钮,当你点击按钮,运算的结果,时间就会传递给后台,而接下来的页面会进行相应判断的显示。下面附上对应代码。
for(int i=0;i<n;i++) { JLabel jb=new JLabel(); jb2[i]=new JLabel(); jb.setText(strarr[3*i]+strarr[3*i+1]); if(strarr[3*i+1].equals(strarr[3*i+2])) { jb2[i].setText("正确"); mi1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for(int i=0;i<n;i++) { if(jb2[i].getText().equals("正确")||jb2[i].getText().equals("正确")||jb2[i].getText().equals("right")) jb2[i].setText("正确"); else jb2[i].setText("错误,答案是:"+strarr[3*i+2]); } } }); mi2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for(int i=0;i<n;i++) { if(jb2[i].getText().equals("正确")||jb2[i].getText().equals("正确")||jb2[i].getText().equals("right")) jb2[i].setText("正确"); else jb2[i].setText("错误,答案是"+strarr[3*i+2]); } } }); mi3.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for(int i=0;i<n;i++) { if(jb2[i].getText().equals("正确")||jb2[i].getText().equals("正确")||jb2[i].getText().equals("right")) jb2[i].setText("right"); else jb2[i].setText("wrong,the answer is :"+strarr[3*i+2]); } } });//计算正确答案 } else { jb2[i].setText("错误,答案是:"+strarr[3*i+2]); cuowu+=1; } jp.add(jb); jp.add(jb2[i]); }//出现错误答案
(3)最终页面
当你在题目页面点击了提交按钮,你的题目和答案会一起提交到后台,后台的计时器会停止计时,并且后台会对你的题目进行分析判断,最后提交给你一份答案页面,以及你答题所用的时间信息,还有你错误的题目的正确答案。下面附上图片和代码。
JPanel jp1=new JPanel(); mi1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jbt.setText("记录"); } }); mi2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jbt.setText("记录"); } }); mi3.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jbt.setText("record"); } });//产生记录 jp1.add(jbt); jp.add(jp1); final JLabel lbl1 = new JLabel(); lbl1.setText("用时 :"+lbl.getText()); mi1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { lbl1.setText("用时:"+lbl.getText()); } }); mi2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { lbl1.setText("用时:"+lbl.getText()); } }); mi3.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { lbl1.setText("time :"+lbl.getText()); } }); jp.add(lbl1); jf.add(jp); } });//累计用时的方法 jb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { } }); } public static void main(String args[]) { new Main(); } } //调用函数
(4)整体实现过程
九、界面模块与计算模块的对接
在思考之后,我们放弃了网页,选择了了GUI类,即使用了图形用户界面来进行UI模块的设计,至于这些各种不同UI模块之间的对接,则是通过事件监听器接口来实现的。
参数传递功能
String n = JOptionPane.showInputDialog( frame, "输入题目的数量(1-1000):" ); String m = JOptionPane.showInputDialog( frame, "输入数值范围(1-10000):" ); String z = JOptionPane.showInputDialog( frame, "输入符号数量(1-10):" );
部分页面截图
十、结对过程
因为工作量较大,我和我的结对小伙伴一早就定下了分工,虽然中间经历了一个小假期,但是我们也不时都在为这个作业而思考,在作业过程中我们遇到了很多困难,有时候一筹莫展,但好在我们一直在努力寻找解决方法,而且沟通良好,两人之间不存在任何嫌隙,最终也都如愿以偿得到了让我们比较满意的结果。下面附上我们的结对照片。
十一、结对编程优缺点
优点:在结对编程中,深刻地体会到了1+1>2的含义,与个人单独编码相比,结对更加的高效,而代码变得更加有质量。当你在敲代码时,有另外一个人在不断提醒监督着你,这让自己克制了一些单独编码时不免会犯的错误,比如惰性和一些基础性的错误,同样,两个人的共进退让我们充满斗志,突破了困难局限,最终完成一项让我们自己满意的项目。
缺点:对于结对编程来说,沟通磨合是非常重要的,一旦没有有效的沟通,那结对编程便很难进行下去,而沟通一直是人与人之间的难题,我想这也算是结对编程所不可避免的缺点吧。另外,每个人编程都有自己的习惯和风格,所以当两个人在一起工作时,难免会产生矛盾就和摩擦,这也是不太容易解决的问题。
各人优缺点:
周紫伊 |
胡雅馨 |
|
优点 |
认真细心,有耐心
|
积极,上进,善于学习,平易近人
|
缺点 |
基础知识薄弱,不善于沟通交流 |
缺点:基础知识不扎实,偶尔懒散 |
十二、最后
这次作业完成的相当费力,也深刻地感觉到了无力,由此发现自己还有很多薄弱的地方,通过这次学习,也学到了不少东西,希望能再接再厉,不断进步。