系统分析与设计结对项目———Wordcount
合作者:201631062513、201631062511
本次作业要求链接地址:https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2188
本次作业代码链接地址:https://gitee.com/linsai/WordCount
一、代码审核及合并
对于代码的审核,主要是自审和互审,在第一次个人项目中我们并没有对自己的代码进行审核,而且测试也没有做的很完善 所以在结对项目中我们要对自己的项目进行审核以及测试,最后将两个人的代码合并实现该项目的扩展和高级功能,最后我们对添加高级功能后的测试就轻松许多。具体的审核如下表:
CODER01:
代码自审 | 代码互审 | 代码合并 |
独自检查文件名,逻辑、以及是否存在不合法的操作 | 首先运行代码,查看代码是否可以通过并达到预期的目的 | 将自审和互审的结果进行讨论把稳定的部分代码进行标记, 与CODER02的代码进行比较, 把稳定性搞的代码留下,并在 任一一个单独项目上进行合并,最后两人一起完成审核 测试,完成扩展功能 |
检查代码在编码格式上是否存在问题 | 其次是构建测试类,调用关键的方法去执行,查看是否能通过运行或者抛出异常 | |
检查在关键代码上是否有异常抛出 | 最后就是测试代码的稳定性,通过多个文件对代码进行测试,查看是否出现异常 |
CODER02:
代码自审 | 代码互审 | 代码合并 |
检查项目中的命名、语法,格式是否合乎规范 | 首先运行代码,查看代码是否可以通过并达到预期的目的 | 将自审和互审的结果进行讨论,把稳定的部分代码进行标记,与CODER01的代码进行比 较,把稳定性搞的代码留下,并在任一一个 单独项目上进行合并,最后两人一起完成 审核,测试,完成扩展功能 |
检查代码编码格式,关键代码是否有异常抛出 | 其次是构建测试类,调用关键的方法去执行,查看是否能通过运行或者抛出异常 | |
查看代码的可读性,以及注释量 | 最后就是测试代码的稳定性,通过多个文件对代码进行测试,查看是否出现异常 |
二、实现扩展功能
在个人项目上,几乎只是实现了基础功能: 统计源文件里面的单词数、字符数、以及行数,但是在java 源文件里面还存在大 量的注释代码,空行码,需要统计以及采用递归处理在该目录下符合条件的文件,该功能的测试和审查均按照上表进行
具体的实现过程参看下表:
psp表格:
SP2.1 | PSP阶段 | 预估耗时 (分钟) | 实际耗时 (分钟) |
Planning | 计划 | 30 | 50 |
· Estimate | · 估计这个任务需要多少时间 | 150 | 200 |
Development | 开发 | 100 | 120 |
· Analysis | · 需求分析 (包括学习新技术) | 100 | 130 |
· Design Spec | · 生成设计文档 |
|
|
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 50 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 50 |
· Design | · 具体设计 | 30 | 40 |
· Coding | · 具体编码 | 150 | 200 |
· Code Review | · 代码复审 | 30 | 40 |
· Test | · 测试(自我测试,修改代码,提交修改) | 50 | 70 |
Reporting | 报告 | 30 | 50 |
· Test Report | · 测试报告 |
|
|
· Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
| 合计 | 790 | 1200
|
表格分析 :上面的一些过程包含了高级功能(图像化界面),该表格也反映了我们在在结对上对于代码复审以及编码花费了大量的时间,主要是在复审时花的时间比较多,各自都在解决各自的问题和讨论,无法达到一致,因此也导致后面的扩展功能也需要两人配合完成,毕竟是把代码进行了合并,但是大部分采用了coder02同学的代码,他的代码相对于coder01的来说显得非常规范,总的来说,显得比较繁琐和复杂。
三、高级功能实现
该结对项目的高级功能是将查询的结果用图像化界面显示出来,由于前面的个人项目采用的编程语言是java,所以,用的是java的图形化界面,基于AWT框架、布局管理器 java swing 、AWT事件处理等技术来实现图形化界面。其次是在windows命令行中输入 wc.exe -x 命令,将直接显示wc的图像化界面,然后就可以进行查询操作,在界面上打开指定源程序文件过后,可以直接全部查询或者分类查询。
图像化界面截图如下:
利用递归循环遍历该目录下的.c源程序文件,实现其扩展功能:
利用递归循环遍历该目录下的.c源程序文件,实现所有功能:
停用表测试功能:
创建TestEfficent测试类,测试代码覆盖率
四、项目的关键代码
高级功能实现关键代码
import java.awt.BorderLayout; import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import javax.swing.ButtonGroup; import javax.swing.JButton; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.awt.event.ActionEvent; import java.awt.GridLayout; import java.awt.TextArea; import javax.swing.JTextField; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JTextPane; import javax.swing.JTabbedPane; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JTextArea; import java.awt.Font; import java.awt.Color; import java.awt.SystemColor; import javax.swing.JRadioButton; public class FrameTest extends JFrame { private JPanel contentPane; private JTextField textField; private JTextField textField_1; private JTextArea textArea; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { FrameTest frame = new FrameTest(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the frame. */ public FrameTest() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 639, 444); contentPane = new JPanel(); contentPane.setForeground(new Color(0, 255, 255)); contentPane.setBackground(new Color(153, 180, 209)); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); textField = new JTextField(); textField.setBounds(64, 41, 292, 24); contentPane.add(textField); textField.setColumns(10); ButtonGroup buttonGroup2 = new ButtonGroup(); JButton button = new JButton("\u9009\u62E9\u6587\u4EF6\u8DEF\u5F84"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JFileChooser chooser = new JFileChooser(); // 设置选择器 chooser.setMultiSelectionEnabled(true); // 设为多选 int returnVal = chooser.showOpenDialog(button); // 是否打开文件选择框 System.out.println("returnVal=" + returnVal); if (returnVal == JFileChooser.APPROVE_OPTION) { // 如果符合文件类型 String filepath = chooser.getSelectedFile().getAbsolutePath();// 获取绝对路径 //String filename = chooser.getSelectedFile().getName(); filepath = filepath.replaceAll("\\\\","/"); textField.setText(filepath); //textField_1.setText(filename + "统计结果为:"); /*System.out.println(filepath); System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName()); // 输出相对路径 */ } } }); button.setBounds(422, 40, 123, 27); contentPane.add(button); JCheckBox charcount = new JCheckBox("\u5B57\u7B26\u6570"); charcount.setBounds(25, 142, 93, 27); contentPane.add(charcount); buttonGroup2.add(charcount); JCheckBox wordcount = new JCheckBox("\u5355\u8BCD\u6570"); wordcount.setBounds(152, 142, 81, 27); contentPane.add(wordcount); buttonGroup2.add(wordcount); JCheckBox lincount = new JCheckBox("\u884C\u6570"); lincount.setBounds(279, 142, 72, 27); contentPane.add(lincount); buttonGroup2.add(lincount); JButton button_1 = new JButton("\u5F00\u59CB\u67E5\u8BE2"); button_1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub if(e.getSource()==button_1){ WordCount WC=new WordCount(0,0,0,0,0,0); String path=textField.getText(); String inputFile=path; String stopFile="result.txt"; try { WC.wc(inputFile, stopFile); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } //获取参数路径 String result = "单词数:"+WC.getWordCount(); String result1 = "字符数:"+WC.getCharCount(); String result2 = "行数:"+WC.getLineCount(); String result3 = "代码行/空行/注释行:"+WC.getCodeCount()+"," +WC.getSpaceCount()+","+WC.getNoteCount(); //textArea.append(result+"\n"+result1+"\n"+result2+"\n"+result3); if(charcount.isSelected()){ textArea.append(result1+"\n"); } if(wordcount.isSelected()){ textArea.append(result+"\n"); } if(lincount.isSelected()){ textArea.append(result2+"\n"); } } } }); button_1.setBounds(422, 142, 113, 27); buttonGroup2.add(button_1); contentPane.add(button_1); JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); tabbedPane.setBounds(14, 23, 5, 5); contentPane.add(tabbedPane); JLabel label = new JLabel("\u7ED3\u679C\u8F93\u51FA\uFF1A"); label.setBounds(14, 200, 87, 18); contentPane.add(label); JLabel lblWc = new JLabel("WC\u5728\u7EBF"); lblWc.setBounds(14, 10, 72, 18); contentPane.add(lblWc); textArea = new JTextArea(); textArea.setBounds(14, 231, 392, 141); contentPane.add(textArea); textField_1 = new JTextField(); textField_1.setBounds(14, 231, 392, 141); contentPane.add(textField_1); textField_1.setColumns(10); JLabel label_1 = new JLabel("\u5206\u7C7B\u67E5\u8BE2\uFF1A"); label_1.setBounds(14, 103, 87, 18); contentPane.add(label_1); } }
扩展功能部分代码:
/统计功能字符数、单词数、行数、代码行/空行/注释行 public static void wc(String inputFile,String stopFile) throws IOException{ String lineString = null; String[] buffer=null; //文件每行 String[] buffer1 = null;//stoplist boolean isNote = false; int notNote=0; //读取停用词表 if(useStop){ File dirr=new File(stopFile); BufferedReader bff = new BufferedReader(new FileReader(dirr)); while((lineString=bff.readLine())!=null){ buffer1=lineString.split(",| "); } bff.close(); } lineString = null; // 读取输入文件inputFile File dir=new File(inputFile); BufferedReader bf = new BufferedReader(new FileReader(dir)); while((lineString=bf.readLine())!=null){ //遇到 , 空格 就结束赋值 buffer=lineString.split(",|;| "); for(int i=0;i<buffer.length;i++){ //使用停用词表则剔除词表内单词,不用则不踢 if(useStop){ if(!buffer[i].equals("")&&!inStop(buffer[i], buffer1)){ wordCount++; } } else{ wordCount++; } } //if(buffer.length!=1) lineCount++; charCount+=(lineString.length()+1); lineString=lineString.trim(); //空行,一个字符的也算空行 if (lineString.matches("^[//s&&[^//n]]*$")||lineString.length()==1) { spaceCount++; } //注释/*的开始 else if (lineString.startsWith("/*") && !lineString.endsWith("*/")||((lineString.startsWith("{/*") ||lineString.startsWith("}/*"))&&!lineString.endsWith("*/"))){ noteCount++; isNote=true; } //没有遇到*/ else if(isNote&&!lineString.endsWith("*/")&&!lineString.startsWith("*/")) { notNote++; noteCount++; } //遇到*/ else if (isNote == true && (lineString.endsWith("*/")||lineString.startsWith("*/"))) { noteCount++; isNote=false; } //注释行 else if (lineString.startsWith("//")|| lineString.startsWith("}//")||lineString.startsWith("{//")|| ((lineString.startsWith("{/*") ||lineString.startsWith("}/*")||lineString.startsWith("/*")) && lineString.endsWith("*/"))) { noteCount++; } else{ codeCount++; } } bf.close(); noteCount-=notNote; codeCount+=notNote; } //判断是否在停用词表内 public static boolean inStop(String str,String[] buffer){ int count=0; for(int i=0;i<buffer.length;i++){ if(str.equals(buffer[i])){ count++; } } if(count>0) return true; else return false; } //遍历文件 public static List<File> getFile(File dir) { List<File> files = new ArrayList<File>(); // 此文件下的所有文件和文件夹集合 File[] subs = dir.listFiles(); for (File file : subs) { if (file.isFile() && file.getName().endsWith(endStr)) { // 把获取到的后缀文件添加到集合中,可以是任何后缀文件 files.add(file); } else if (file.isDirectory()) //如果是目录,就进行递归 files.addAll(getFile(file)); } return files; } }
五、设计流程图
六项目总结:
本次的结对项目给我们最大的影响实在合作方面,因为我们要把我们的代码进行互审和合并,在完成的过程
中会出现很多的错误,毕竟代码是两个人的,所以我们就先负责自己原来代码,在自己原来代码的基础上尝试实现
扩展功能,然后在做图形化界面。现在了解到读别人的代码是非常难的,思路不同,编码规范也不一样,自己有自
己的风格。还是需要不断的沟通尝试去理解别人的代码,但是两个人一起配合做还是有非常好的,大大提高了编程
的效率,而且有问题也可以一起解决,可以尝试不同的思路。