结对作业——WordCount进阶版

结对作业——WordCount进阶版

标签(空格分隔): 软件工程


Task1:Fork仓库的码云地址

  • 博客作业要求地址:https://www.cnblogs.com/happyzm/p/9626779.html
  • 结对项目码云地址:https://gitee.com/holmec/PairProject-Java/tree/master/
  • 结队伙伴:201621123033 姚雯婷
    博客地址

Task2:PSP表格

PSP2.1个人开发流程预估耗费时间(分钟)实际耗费时间(分钟)
Planning计划1020
· Estimate明确需求和其他相关因素,估计每个阶段的时间成本2020
Development开发420300
· Analysis需求分析 (包括学习新技术)6030
· Design Spec生成设计文档2025
· Design Review设计复审2020
· Coding Standard代码规范4010
· Design具体设计2026
· Coding具体编码120150
· Code Review代码复审2025
· Test测试(自我测试,修改代码,提交修改)10070
Reporting报告80110
·测试报告2025
·计算工作量1015
·并提出过程改进计划2015

Task3:解题思路描述

题目的需求分析:

WordCount 结对项目在个人项目的基础上,增加新的功能如下:

  • 词组统计:能统计文件夹中指定长度的词组的词频
  • 自定义输出:能输出用户指定的前n多的单词与其数量
    为了实现上述软件,我们首先要在个人项目基础上增量改进,实现一个Core模块,并基于Core模块实现在命令行测试程序中支持下述命令行参数(原有命令行参数不变)

  • -i 参数设定读入的文件路径
    wordCount.exe -i [file]

  • -m 参数设定统计的词组长度
    wordCount.exe -m [number]

  • -n参数设定输出的单词数量
    wordCount.exe -n [number]

  • -o参数设定生成文件的存储路径
    wordCount.exe -o output.txt


思路分析:

这道题是继续上次个人作业的,比起之前多了两个功能,同时加上了前端界面的设计。因为是结对编程,首先我们在代码的确定上做了一些交谈。

  • 我的代码在功能实现的基础上,对于文件类的读取比较全面,有考虑到打开or写入的文件为空文件,但是在其他特殊符号的处理上没有结对小伙伴的全面。
  • 而她的是在特殊符号上做的全面,但是没有考虑到打开空文件的情况

经过一些讨论,我们决定在基础上采用她的代码,进行新功能的添加。她来负责添加新功能,实现用命令行来执行相关操作,我来负责单元测试,用netBean来实现GUI界面。

Task4:设计实现过程

一、相关类的设计

  针对这个要求,得到一个主函数,两个类,其中:

  • Count类:进行字符数量、行数、单词数、词频的统计。
  • File类:进行文件内容的读取,以及处理结果的写入。
  • read类:将string类型的字符串转换成ArrayList类型。
  • Main类:结合实际情况,创建以上两种对象,进行方法的调用,实现题目要求。
  • CountTest:用于单元测试。

二、相关函数的设计

Count:

  1. count.CountChars(); //字符数统计
  2. count.CountWords();//单词数统计
  3. count.CountLine();//有效行统计
  4. count.WordTop(n,CountWords);//单词频率统计,统计数量排名前n的单词
  5. count.CountPhrase(m);//统计长度为m词组

File:

  1. file.readfile(path);//读出文件内容变成ArrayList格式类型
  2. file.writefile(save, CountChars, CountWords, CountLine, wordtop, CountPhrase);//按照要求和给出的路径写入指定文件

read:

  1. re.readfile(line);//将string类型的字符串转换成ArrayList类型

三、GUI界面设计

使用netBeans设计其相关界面布局,具有打开指定文件,保存为指定文件,并可以更改参数m和参数n的值进行统计。页面样式如下:

1099326-20181009163441345-1723703600.png

1099326-20181009163444596-1796778148.png


Task5:代码说明

1. Read类中readfile(String line)函数

  该函数用于将string类型的字符串转换成ArrayList类型,由于在netBeans的文本框类型中的getText()得到的是整个字符串,而我的队友写的处理字符的count类是针对ArrayList类型,所以需要进行转换才可以嵌套

public class Read { //将string类型的字符串转换成ArrayList<String>类型
    public ArrayList<String> readfile(String line){
    ArrayList<String> arrylist=new ArrayList<>();
    String[] everyword = line.split("\n");//用空格作为分割
    System.out.println("everyword.length_"+everyword.length);
    String str;
       for(int j=0;j<everyword.length;j++){
           arrylist.add(everyword[j]);//添加到ArrayList<String>类型数组
       }
        
    System.out.println(arrylist);
     
                
        return arrylist;
    }
}

2.GUI界面主要函数

  • 触发按钮功能
    这一类的方法是,当用户设置好内容点击开始统计按钮后,所绑定的函数进行调用,并在文本框中进行展示
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        // TODO add your handling code here:
        int n1 = (int) n.getValue();//获取微调器的内容
        int m1 = (int) m.getValue();//获取微调器的内容
        System.out.println(n1);
        System.out.println(m1);
        String line = jTextArea2.getText();//获取文本区域的内容
        System.out.println("line_" + line);
        // line = line.replace('\n',' ');
        Read re = new Read();
        ArrayList<String> arrylist = new ArrayList<>();
        arrylist = re.readfile(line);

        System.out.println(arrylist + "!!!!!!!!!!");

        Count count = new Count(arrylist);
        int CountChars = count.CountChars();
        int CountWords = count.CountWords();
        int CountLine = count.CountLine();
        System.out.println(CountChars);
        System.out.println(CountWords);
        System.out.println(CountLine);
        ArrayList<Entry<String, Integer>> wordtop = count.WordTop(n1, CountWords);
        Map<String, Integer> CountPhrase = count.CountPhrase(m1);

        String total;
        String str1 = "characters:" + CountChars;
        String str2 = "words:" + CountWords;
        String str3 = "lines:" + CountLine;

        total = str1 + "\n" + str2 + "\n" + str3 + "\n";

        for (int i = 0; i < wordtop.size(); i++) {//遍历输出
            Map.Entry<String, Integer> e = wordtop.get(i);
            total = total + e.getKey() + ":" + e.getValue() + "\r\n";
        }
        for (Entry<String, Integer> Phrase : CountPhrase.entrySet()) {//遍历输出
            total = total + Phrase.getKey() + ":" + Phrase.getValue() + "\r\n";
        }
        jTextArea1.setText(total);//将字符串写入到文本区域中

    }//GEN-LAST:event_jButton2ActionPerformed
  • 打开文件功能
    这个用于设置打开文件时的选择框。
 private void jRadioButtonMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItem1ActionPerformed
        // TODO add your handling code here:
        
        f = new Frame("my window");// 创建窗体对象
        f.setBounds(300, 100, 650, 600);// 设置窗体位置和大小
        open = new FileDialog(f, "打开", FileDialog.LOAD);

        open.setVisible(true);//显示打开文件对话框

        String dirpath = open.getDirectory();//获取打开文件路径并保存到字符串中。
        String fileName = open.getFile();//获取打开文件名称并保存到字符串中

        if (dirpath == null || fileName == null)//判断路径和文件是否为空
        {
            return;
        } else {
            jTextArea2.setText(null);//文件不为空,清空原来文件内容。
        }
        java.io.File file = new java.io.File(dirpath, fileName);//创建新的路径和名称

        try {
            BufferedReader bufr = new BufferedReader(new FileReader(file));//尝试从文件中读东西
            String line = null;//变量字符串初始化为空
            while ((line = bufr.readLine()) != null) {
                jTextArea2.append(line + "\r\n");//显示每一行内容
            }
            bufr.close();//关闭文件
        } catch (FileNotFoundException e1) {
            // 抛出文件路径找不到异常
            e1.printStackTrace();
        } catch (IOException e1) {
            // 抛出IO异常
            e1.printStackTrace();
        }
    }//GEN-LAST:event_jRadioButtonMenuItem1ActionPerformed

  • 保存文件功能
    这个用于将运行结果的内容保存到指定地点的指定文件中。
private void jRadioButtonMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItem2ActionPerformed
        // TODO add your handling code here:
        save = new FileDialog(f, "保存", FileDialog.SAVE);
        if (file == null) {
            save.setVisible(true);//显示保存文件对话框
            String dirpath = save.getDirectory();//获取保存文件路径并保存到字符串中。
            String fileName = save.getFile();获取打保存文件名称并保存到字符串中

            if (dirpath == null || fileName == null)//判断路径和文件是否为空
            {
                return;//空操作
            } else {
                file = new java.io.File(dirpath, fileName);//文件不为空,新建一个路径和名称
            }
        }
        try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(file));

            String text = jTextArea1.getText();//获取文本内容
            bw.write(text);//将获取文本内容写入到字符输出流

            bw.close();//关闭文件
        } catch (IOException e1) {
            //抛出IO异常
            e1.printStackTrace();
        }
    }//GEN-LAST:event_jRadioButtonMenuItem2ActionPerformed

Task6:单元测试

  根据以上函数,设置了一些测试点,尽可能罗列出各种情况:

  • 字符数为空,但有其他换行等符号
  • 中文和英文混合文件
  • 完全的英文文件
  • 完全的英文文件,大小写混合
  • 完全的英文文件,无合法单词

对应设置的文件为:

  • test1:完全的空文件,但是有回车空格等符号
  • test2:中文和英文混合文件
  • test3:纯英文文件,完全小写
  • test4:纯英文文件,大小写混合
  • test5:英文、数字、特殊符号混合

测试代码:

class CountTest {

    String file1 = "D:\\soft-ware\\PersonalProject-Java\\201621123037qinyu\\WordCount_2\\test1.txt";
    String file2 = "D:\\soft-ware\\PersonalProject-Java\\201621123037qinyu\\WordCount_2\\test2.txt";
    String file3 = "D:\\soft-ware\\PersonalProject-Java\\201621123037qinyu\\WordCount_2\\test3.txt";
    String file4 = "D:\\soft-ware\\PersonalProject-Java\\201621123037qinyu\\WordCount_2\\test4.txt";
    String file5 = "D:\\soft-ware\\PersonalProject-Java\\201621123037qinyu\\WordCount_2\\test5.txt";
    
    
    @BeforeEach
    void setUp() throws Exception {
    }

    
    @Test
    void testCountChars() throws IOException {
        File file=new File();
        ArrayList<String> line1=new ArrayList<>();
        ArrayList<String> line2=new ArrayList<>();
        ArrayList<String> line3=new ArrayList<>();
        ArrayList<String> line4=new ArrayList<>();
        
        line1=file.readfile(file1);
        line2=file.readfile(file2);
        line3=file.readfile(file3);
        line4=file.readfile(file4);
        
        Count count1=new Count(line1);
        Count count2=new Count(line2);
        Count count3=new Count(line3);
        Count count4=new Count(line4);
        
        int CountChars1=count1.CountChars();
        int CountChars2=count2.CountChars();
        int CountChars3=count3.CountChars();
        int CountChars4=count4.CountChars();
        
    //  assertEquals(CountChars1,0);
        assertEquals(CountChars2,24);
        assertEquals(CountChars3,56);
        assertEquals(CountChars4,200);
        
    }

    @Test
    void testCountWords() throws IOException {
        File file=new File();
        ArrayList<String> line1=new ArrayList<>();
        ArrayList<String> line2=new ArrayList<>();
        ArrayList<String> line3=new ArrayList<>();
        ArrayList<String> line4=new ArrayList<>();
        
        line1=file.readfile(file1);
        line2=file.readfile(file2);
        line3=file.readfile(file3);
        line4=file.readfile(file4);
        
        Count count1=new Count(line1);
        Count count2=new Count(line2);
        Count count3=new Count(line3);
        Count count4=new Count(line4);
        
        int CountWords1=count1.CountWords();
        int CountWords2=count2.CountWords();
        int CountWords3=count3.CountWords();
        int CountWords4=count4.CountWords();
        
        //assertEquals(CountWords1,5);
        assertEquals(CountWords2,1);
        assertEquals(CountWords3,9);
        assertEquals(CountWords4,27);
    }

    @Test
    void testCountLine() throws IOException {
        File file=new File();
        ArrayList<String> line1=new ArrayList<>();
        ArrayList<String> line2=new ArrayList<>();
        ArrayList<String> line3=new ArrayList<>();
        ArrayList<String> line4=new ArrayList<>();
        
        line1=file.readfile(file1);
        line2=file.readfile(file2);
        line3=file.readfile(file3);
        line4=file.readfile(file4);
        
        Count count1=new Count(line1);
        Count count2=new Count(line2);
        Count count3=new Count(line3);
        Count count4=new Count(line4);
        
        int CountLine1=count1.CountLine();
        int CountLine2=count2.CountLine();
        int CountLine3=count3.CountLine();
        int CountLine4=count4.CountLine();
        
        //assertEquals(CountLine1,5);
        assertEquals(CountLine2,6);
        assertEquals(CountLine3,4);
        assertEquals(CountLine4,12);
    }

    @Test
    void testWordTop() throws IOException {
        /*File file=new File();
        ArrayList<String> line=new ArrayList<>();
        int n = 10;//-n参数设定输出的单词数量
        line=file.readfile(file1);
        
        Count count=new Count(line);
        int CountWords=count.CountWords();
        
        int WordTop=count.WordTop(n,CountWords).size();
        
        assertEquals(WordTop,10);*/
        
    }

    @Test
    void testCountPhrase() throws IOException {

    
        
/*
        File file=new File();       
        ArrayList<String> line=new ArrayList<>();
        line=file.readfile(file4);
        //System.out.println(line);
        Count count=new Count(line);
        Map<String,Integer> CountPhrase=count.CountPhrase(4);*/
        
        File file=new File();       
        ArrayList<String> line=new ArrayList<>();
        line=file.readfile(file4);
        Count count=new Count(line);
        int CountChars=count.CountChars();
        int CountWords=count.CountWords();
        int CountLine=count.CountLine();
        //ArrayList<Entry<String, Integer>> wordtop=count.WordTop(n,CountWords);
        Map<String,Integer> CountPhrase=count.CountPhrase(4);
        
        /*Map<String,Integer> w1 = new HashMap<String,Integer>();
        Map<String,Integer> w2 = new HashMap<String,Integer>();*/
        Map<String,Integer> w3 = new HashMap<String,Integer>();
    //  Map<String,Integer> w4 = new HashMap<String,Integer>();
    
        w3.put("dreams will come true", 1);
        w3.put("live through your pain", 1);
        w3.put("trying times will pass", 1);
        w3.put("your dreams will come", 1);
        
        System.out.println("CountPhrase");
        System.out.println(CountPhrase);
        
        System.out.println("w3");
        System.out.println(w3);
        
        assertEquals(CountPhrase, w3);
        
    }

}

测试结果:

错误问题

1099326-20181009173638795-1483245289.png

在测试testCountPhrase()中,运用如下代码测试结果一直出错,输出的部分也可以看出CountPhrase中的内容一直为空,但是在之前写好的main函数中同样调用却不会出问题。

测试代码:

File file=new File();       
        ArrayList<String> line=new ArrayList<>();
        line=file.readfile(file4);
        //System.out.println(line);
        Count count=new Count(line);
        Map<String,Integer> CountPhrase=count.CountPhrase(4);

输出结果:

CountPhrase
{}
w3
{dreams will come true=1, live through your pain=1, trying times will pass=1, your dreams will come=1}
解决过程

经过反复输出核对代码,发现在count类中有设置一个Map<String,Integer> map=new HashMap<String,Integer>();,并且这个参数在以下两个方法中都有被调用。

1099326-20181010001624529-910141648.png

1099326-20181009173711147-178267987.png

1099326-20181009173715724-1740118752.png

故,测试代码:

File file=new File();       
        ArrayList<String> line=new ArrayList<>();
        line=file.readfile(file4);
        Count count=new Count(line);
        int CountChars=count.CountChars();
        int CountWords=count.CountWords();
        int CountLine=count.CountLine();
        Map<String,Integer> CountPhrase=count.CountPhrase(4);

    

测试结果:

1099326-20181009173901264-819414349.png

分值覆盖率截图:

1099326-20181009174057073-738346302.png

Task7:对netBeans进行文件内容测试截图

运行结果:

test1.txt

1099326-20181009183334101-1792591519.png


test2.txt
1099326-20181009183402934-1651931198.png

1099326-20181009183406779-28089152.png


test3.txt
1099326-20181009183410181-1402361674.png
1099326-20181009183414763-1270824054.png


test4.txt
1099326-20181009183417839-1382944429.png
1099326-20181009183421226-1933145813.png


test5.txt

1099326-20181009183425825-1200493616.png
1099326-20181009183429256-1191389911.png



1099326-20181009183435645-509644937.png

1099326-20181009183438013-196627542.png


Task8:效能分析

1099326-20181009201210624-741760106.png

1099326-20181009201213643-1253601948.png

1099326-20181009201218118-1692082991.png

1099326-20181009201225040-110721090.png


Task9:心得体会

1099326-20181009195711991-1617123998.png

1099326-20181009195718677-1111409776.png

1099326-20181009195724117-1924121954.png

  在这次实验中,双人结对编程将编写代码从单人奋斗变成了一起奋斗,这中间我们有很多次沟通交流,很多次选择实现方法,还有任务的分配。通过这次实验我理解了书上写的编写代码的规范,如果编写代码规范上不够严格处理,那么对于结队的队友是一个极大的考验。。。花费在理解代码上的时间会更多。不过总的来说还是完成了任务,虽然因为假期我们回家导致两个人分割异地,但是我们还是坚持在QQ上聊天以及通视频,完成两个程序员之间的亲密交流。总的来说,两人合作的话缺点在于如果不能及时沟通,可能会导致浪费时间的不必要做功,但是可以制定更加完备的方案,考虑问题更加全面,如果再来一次还是结队能学到对方的一些小诀窍,做事上的思维宽度可以拓宽。

转载于:https://www.cnblogs.com/qin-yu/p/9756969.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值