Coding克隆地址:https://git.coding.net/FrrLolix/CalGUI.git
伙伴博客:http://www.cnblogs.com/FrrLolix/p/8763072.html
目录:
一、前言
二、计划时间——PSP
三、接口设计
四、接口实现
五、性能分析
六、单元测试
七、异常处理
八、模块设计
九、模块对接
十、结对成员
十一、结对编程思考
十二、实际时间——PSP
一、前言
首先我很感谢我的队友,谢谢他的努力,放弃自己休息的时间,我们才能做成这个项目,我对于这个完成这个项目的能力很是欠缺,通过这次的作业,提高团队合作力和代码能力。
二、PSP
PSP |
任务内容 |
计划时间(min) |
Planning |
计划 |
30 |
Estimate |
估计这个任务需要多少时间,并规划大致工作步骤 |
30 |
Development |
开发 |
35*60+25 |
Analysis |
需求分析 |
60 |
Design Spec |
生成文档 |
0 |
Design Review |
设计复审 |
2*60 |
Coding Standard |
代码规范 |
10 |
Design |
具体设计 |
12*60 |
Coding |
具体编码 |
2*8*60 |
Code Review |
代码复审 |
4*60 |
Test |
测试 |
15 |
Reporting |
报告 |
5.5*60 |
Test Report |
测试报告 |
60 |
Size Measurement |
计算工作量 |
30 |
Postmortem& ProcessImprovement Plan |
事后总结, 并提出过程改进计划 |
4*60 |
三、接口设计
在《构建之法》书中没有找到有关信息,希望老师在设计要求的时候,可以告诉我们页数。我在网上查阅了资料。
Information Hiding信息隐藏:信息隐藏指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。
Interface Design接口设计:是传统的后勤保障的一种要素也是一种后勤功能。
Loose Coupling松耦合:系统通常是基于消息的系统,此时客户端和远程服务并不知道对方是如何实现的。客户端和服务之间的通讯由消息的架构支配。只要消息符合协商的架构,则客户端或服务的实现就可以根据需要进行更改,而不必担心会破坏对方。
本次作业采用的是网页制作,整体采用MVC模型MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。本次作业进行了模块化编程,运算模块和界面模块相对较独立,尽量做到了低耦合度。让判断正误和计时以及条件受限放到前端制作,减少服务器的负担。
四、接口实现
我们的项目中界面套界面。即是亮点又是污点,亮点在于方法简单,实现方便,容易掌握。同时这也是一个不好之处,导致程序无法分解,耦合度太高,后期维护困难。
讲真,这个项目对于我们来说,能完成已经是竭尽全力,在优化性能时尽管有些抵触,但也算尽力,尽量减少内存占用率,减少嵌套循环和数组过大带来的资源浪费。在生成计算式时,不符合要求的计算式需要舍弃,在数值较大时,十分容易造成资源的浪费,因此我们在数值较大时,尽量限制了乘法时数的大小,尽量避免连续多次弃用。
六、单元测试
测试Command类
设计思路:
在main方法中实现了对输入参数的解析和对输入参数异常的报错,所以测试这个部分的函数最主要的就是构造不同的异常情况,同时也不要忘记测试参数正确时的情况,因为这也是代码的一部分(单元测试中第一次就是因此覆盖率较低)。
单元测试代码展示(测试Command.java):
import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class CommandTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @AfterClass public static void tearDownAfterClass() throws Exception { } @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testNewExpSome() { for(int i=0;i<6;i++){ Command.expression(false, 200, 20, 6); } for(int i=0;i<24;i++){ Command.expression1(true, 200, 20, 4); Command.exprission2(true, 200, 20, 4); Command.expression3(true, 200, 20, 4); } System.out.println("Command程序正常!"); } @Test public void testDivideExactly() { } } CommandTest
七、异常处理:
if(radioButtonMenuItem01.isSelected()){flag='a';} if(radioButtonMenuItem02.isSelected()){flag='b';} if(radioButtonMenuItem03.isSelected()){flag='c';} String n = JOptionPane.showInputDialog( frame, "输入题目的数量(1-1000):" ); String m = JOptionPane.showInputDialog( frame, "输入数值范围(1-10000):" ); String z = JOptionPane.showInputDialog( frame, "输入符号数量(1-10):" ); if(n==null||n.equals("")&&m==null||m.equals("")&&z==null||z.equals("")){ textArea.append("取消生成,请检查数值\n"); }
if(arithExpress.isEmpty()){ JOptionPane.showMessageDialog( frame, "没有读取到默认题库,请先生成或者打开本地题库", "消息标题", JOptionPane.WARNING_MESSAGE );
八、模块设计
整体思路:
导航页和获得出题参数页使用了同种方式来生成用户界面,代表导航页和出题参数页的类继承了JFrame类,在内部类中加入页面需要的各种组件,并将这个内部类的对象加入到外部类的实例中,在这里以计算页的代码为例展示这种方式(因代码太长所以只展示一部分):
public void generateExpressionA(int num,int m,int z){ char[] operator=new char[]{'+','-','*','÷'}; ArrayListexpression=new ArrayList (); for(int i=0;i ){ int n=z; //3-5个运算符 int[] number=new int[n+1]; for(int j=0;j<=n;j++){ number[j]=random.nextInt(m)+1; //4-5个数字 } String ex=new String(); for(int j=0;j ){ int s=random.nextInt(4);//随机选择某个运算符 ex+=String.valueOf(number[j])+String.valueOf(operator[s]);///5+4/ } ex+=String.valueOf(number[n]); String result=calculate.solution(ex); if(decideNegDiv(Float.parseFloat(result))){ expression.add(ex+="="+Float.parseFloat(result)); }else{ i--; } } doFile.WriteToFile("result.txt",expression); } /** * 生成带括号运算结果非负,非小数的运算式 * @param num */ public void generateExpressionB(int num,int m,int z){ char[] operator=new char[]{'+','-','*','÷'}; ArrayList expression=new ArrayList (); for(int i=0;i ){ int n=z; //3-5个运算符 int[] number=new int[n+1]; for(int j=0;j<=n;j++){ number[j]=m; //4-5个数字 } String ex=new String(); int c=random.nextInt(3); for(int j=0;j ){ switch(c){ case 0: if(j==0){//(6- ex+='('+String.valueOf(number[j])+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } if(j==1){ ex+=String.valueOf(number[j])+')'+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } else{ ex+=String.valueOf(number[j])+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } case 1: if(j==1){//3-(4- ex+='('+String.valueOf(number[j])+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } if(j==2){ ex+=String.valueOf(number[j])+')'+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } else{ ex+=String.valueOf(number[j])+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } case 2: if(j==2){//5-6-(7- ex+='('+String.valueOf(number[j])+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } if(j==3){//5-6-(7-5)- ex+=String.valueOf(number[j])+')'+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } else{ ex+=String.valueOf(number[j])+String.valueOf(operator[random.nextInt(4)]);///5+4/ break; } } ex+=String.valueOf(number[j])+String.valueOf(operator[random.nextInt(4)]);///5+4/ } ex+=String.valueOf(number[n]); if(ex.indexOf('(')!=-1){ if(ex.indexOf(')')==-1){ ex+=")"; } } String result=calculate.solution(ex); if(decideNegDiv(Float.parseFloat(result))){ expression.add(ex+="="+Float.parseFloat(result)); }else{ i--; } } doFile.WriteToFile("result.txt",expression); }
九、模块对接
读取文件的类:
public ArrayListReadFile(String path) { ArrayList tempList=new ArrayList (); try { BufferedReader br = new BufferedReader(new FileReader(path)); String line; while((line=br.readLine())!=null){ tempList.add(line); } br.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } return tempList; } /** * 读取文件最后N行 * 根据换行符判断当前的行数, * 使用统计来判断当前读取第N行 * @param path 待文件路径 * @param numRead 读取的行数 * @return List */ public ArrayList readLastNLine(String path, long numRead) { File file=new File(path); ArrayList result = new ArrayList (); long count = 0; if (!file.exists() || file.isDirectory() || !file.canRead()){ return null; } RandomAccessFile fileRead = null; try{ fileRead = new RandomAccessFile(file, "r"); long length = fileRead.length(); if (length == 0L){ return result; } else{ long pos = length - 1; while (pos > 0){ pos--; fileRead.seek(pos); if (fileRead.readByte() == '\n'){ String line = fileRead.readLine(); result.add(line); count++; if (count == numRead){ break; } } } if (pos == 0){ fileRead.seek(0); result.add(fileRead.readLine()); } } } catch (IOException e){ e.printStackTrace(); } finally{ if (fileRead != null){ try{ fileRead.close(); } catch (Exception e){ } } } return result; }
十、结对成员
1、樊融:优点:技术强;聪明;乐观。缺点:做事不认真。
2、王玥莹:优点:认真,上进,创造性思维强。缺点:模块化思维欠缺。
十一、结对编程思考
结对编程有好处:
一、结对编程可以相互学习互相鼓励
二、分工明确,可以提高做事效率
三、增强两个人的关系,增强合作能力、增强代码理解能力。
四、在出现错误时,伙伴可以及时发现并且指出,少走弯路
结对编程有坏处:
一、需要大量的交流,如果交流沟通不到位,项目将寸步难行。
二、可能会出现思路的分歧,导致两人代码出现分歧,难以结合。
三、两人分工的不均匀,有可能出现技术强带技术弱做项目的情况。
十二、PSP
PSP |
任务内容 |
完成时间(min) |
Planning |
计划 |
60 |
Estimate |
估计这个任务需要多少时间,并规划大致工作步骤 |
60 |
Development |
开发 |
45*60 |
Analysis |
需求分析 |
45 |
Design Spec |
生成文档 |
0 |
Design Review |
设计复审 |
3*60 |
Coding Standard |
代码规范 |
15 |
Design |
具体设计 |
12*60 |
Coding |
具体编码 |
3*8*60 |
Code Review |
代码复审 |
4*60 |
Test |
测试 |
60 |
Reporting |
报告 |
9*60 |
Test Report |
测试报告 |
0 |
Size Measurement |
计算工作量 |
60 |
Postmortem& ProcessImprovement Plan |
事后总结, 并提出过程改进计划 |
8*60
|