• 第三次作业


    一、我们Fork仓库的Github项目地址

    结对使用的Github项目地址:https://github.com/xuyixiaowoaini/WordCount.git

    结对伙伴的作业地址:https://www.cnblogs.com/CHIQING123/p/10659152.html

    二、PSP表格

    PSP2.1

    Personal Software Process Stages

    预估耗时(分钟)

    实际耗时(分钟)

    Planning

    计划

     5  5

    · Estimate

    · 估计这个任务需要多少时间

     5  5

    Development

    开发

     720  810

    · Analysis

    · 需求分析 (包括学习新技术)

     60  120

    · Design Spec

    · 生成设计文档

     10  10

    · Design Review

    · 设计复审 (和同事审核设计文档)

     10  10

    · Coding Standard

    · 代码规范 (为目前的开发制定合适的规范)

     10  10

    · Design

    · 具体设计

     30  60

    · Coding

    · 具体编码

     360  360

    · Code Review

    · 代码复审

     60  60

    · Test

    · 测试(自我测试,修改代码,提交修改)

     180  180

    Reporting

    报告

     130  190

    · Test Report

    · 测试报告

     60  120

    · Size Measurement

    · 计算工作量

     10  10

    · Postmortem & Process Improvement Plan

    · 事后总结, 并提出过程改进计划

     60  60
     

    合计

     855  1005

    三、计算模块接口的设计与实现过程。

    1、设计

    这个项目有五个基本功能点:计算Input文件的字符数、单词总数、有效行数、单词出现次数并排序,以及输出到Result文件。

    这些功能总体由三个类来完成:

    (1)WordIO(实现输入文件以及输出文件的功能)

    (2)WordTrie(实现计算单词出现次数并排序的功能)

    (3)WordCalculate(实现计算字符数、单词总数、有效行数的功能)

    大致结构如下:

    2、如何体现“Design by Contract”、“Information Hiding”、 “Interface Design”、 “Loose Coupling”等原则的

    (1)Design By Contract(契约式设计):

    按照某种规定对一些数据等作出约定,如果超出约定,程序将不再运行。

    如何体现:一个契约设计,就是约束了某个方法调用的要求、以及返回的承诺。那么,设计在正确的输入下,能够得到正确的输出,否则程序将报错。

    (2)Information Hiding(信息隐藏):

    在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。

    如何体现:类与类之间通过接口类访问。

    (3)Interface Design(接口设计):

    对接口的名字,功能,接口与接口间的继承关系进行设计;好的接口设计可以增强代码可读性,易用性,可更改性。

    如何体现:设计接口,规范接口名字,注重接口逻辑。

     (4)Loose Coupling 松耦合

    软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息。

    如何体现:增加接口。

    四、代码复审过程。

    1、代码规范

    参考https://wenku.baidu.com/view/b5be911b6bd97f192279e9bd.html

    2、代码互审情况、发现的问题

     我们完成这个项目时基本是在一起讨论编程的,因此最后没有发现什么大的问题,只是合并时改了不同的参数,以及对代码规范的问题进行了一些修改。

    五、计算模块接口部分的性能改进。

    1、性能改进

        在整体编程结束后,进行性能分析与改进是非常有必要的。虽然在小规模的数据下,功能的实现是不太会涉及到优化算法的。但是,个别特例或者是大规模的数据却需要对程序进行性能的优化改进。我查询资料找到这些方法:

    (1)消除循环的低效率

    (2)减少过程调用

    (3)消除不必要的存储器引用

    (4)循环展开

    (5)提高并行性

        在性能改进方面则运用了这些方法来改进以提高性能。

    2、性能分析图

    六、代码说明。

    在关键部分已加入注释说明。

    (1)WordIO类,实现输入文件以及输出文件的功能

     1 public class WordIO
     2     {
     3         public string pathIn;
     4         public string pathOut;
     5 
     6         //按行读取输入文件并统计
     7         public WordCalculate Input(WordCalculate datanumber, WordTrie wtrie)
     8         {
     9             FileStream fs = null;
    10             StreamReader sr = null;
    11             String dataline = String.Empty;
    12             try
    13             {
    14                 fs = new FileStream(this.pathIn, FileMode.Open);
    15                 sr = new StreamReader(fs);
    16                 while ((dataline = sr.ReadLine()) != null)
    17                 {
    18                     datanumber.Calculate(dataline, wtrie);  //按行统计数据
    19                 }
    20             }
    21             catch { Console.WriteLine("文档读取失败!"); }
    22             finally
    23             {
    24                 if (sr != null) { sr.Close(); }
    25                 if (fs != null) { fs.Close(); }
    26             }
    27             return datanumber;
    28         }
    29 
    30         //将统计数据输出并写到输出文件
    31         public void Output(WordCalculate datanumber, WordTrie wtrie)
    32         {
    33             FileStream fs = null;
    34             StreamWriter sw = null;
    35             List<WordTrie.ListUnit> WordList = new List<WordTrie.ListUnit>();
    36             try
    37             {
    38                 fs = new FileStream(this.pathOut, FileMode.Create);
    39                 sw = new StreamWriter(fs);
    40                 WordList = wtrie.Sort();
    41                 sw.WriteLine("字符总数为:{0}", datanumber.charactersnumber);
    42                 sw.WriteLine("单词总数为:{0}", datanumber.wordsnumber);
    43                 sw.WriteLine("有效行数为:{0}", datanumber.linesnumber);
    44                 sw.WriteLine("\n词频\t单词\n");
    45                 Console.WriteLine("字符总数为:{0}", datanumber.charactersnumber);
    46                 Console.WriteLine("单词总数为:{0}", datanumber.wordsnumber);
    47                 Console.WriteLine("有效行数为:{0}", datanumber.linesnumber);
    48                 Console.WriteLine("\n词频\t单词\n");
    49                 for (int i = 0; (i < 10 && i < WordList.Count); i++)
    50                 {
    51                     sw.WriteLine("{0}\t{1}",WordList[i].WordNum, WordList[i].Word);
    52                     Console.WriteLine("{0}\t{1}",WordList[i].WordNum,  WordList[i].Word);
    53                 }
    54             }
    55             catch { Console.WriteLine("文档写入失败!"); }
    56             finally
    57             {
    58                 if (sw != null) 
    59                 { 
    60                     sw.Close(); 
    61                 }
    62                 if (fs != null) 
    63                 {
    64                     fs.Close();
    65                 }
    66             }
    67         }
    68     }

    (2)WordTrie类,利用Trie树节点实现计算单词出现次数并排序的功能(只展示关键函数)

     1 //获取单词词频
     2         public int WordCount(string word)
     3         {
     4             return GetCount(word, true);
     5         }
     6 
     7         private int GetCount(string str, bool isword)
     8         {
     9             if (string.IsNullOrEmpty(str))
    10             {
    11                 return -1;
    12             }
    13             TrieNode node = _Root;
    14             for (int i = 0, len = str.Length; i < len; i++)
    15             {
    16                 char pos = str[i];
    17                 if (!node.Sons.ContainsKey(pos)) return 0;
    18                 else node = node.Sons[pos];
    19             }
    20             return isword ? node.WordNum : node.PrefixNum;
    21         }
     1 //词频排序
     2         public List<ListUnit> Sort()
     3         {
     4             TrieNode node = _Root;
     5             List<ListUnit> WordList = new List<ListUnit>();
     6             WordList = WordPreOrder(node, WordList);
     7             //按词频降序排列,若词频相等按字典序排列
     8             WordList.Sort((a, b) =>
     9             {
    10                 if (a.WordNum.CompareTo(b.WordNum) != 0)
    11                     return -a.WordNum.CompareTo(b.WordNum);
    12                 else
    13                     return a.Word.CompareTo(b.Word);
    14             });
    15             return WordList;
    16         }

    (3)WordCalculate(实现计算字符数、单词总数、有效行数的功能)

     1 public class WordCalculate
     2     {
     3         public long charactersnumber = 0;  //统计数据:字符数
     4         public long wordsnumber = 0;  //统计数据:单词数
     5         public long linesnumber = 0;  //统计数据:行数
     6         //数据统计
     7         public void Calculate(string dataline, WordTrie wtrie)
     8         {
     9             if (string.IsNullOrEmpty(dataline)) return;
    10             string word = null;
    11             for (int i = 0, len = dataline.Length; i < len; i++)
    12             {
    13                 char unit = dataline[i];
    14                 if (unit >= 65 && unit <= 90) 
    15                 { 
    16                     unit = (char)(unit + 32); 
    17                 }  //大写字母转换成小写
    18                 if ((unit >= 48 && unit <= 57) || (unit >= 97 && unit <= 122))
    19                 {
    20                     word = String.Concat(word, unit);
    21                 }
    22                 else
    23                 {
    24                     if (!string.IsNullOrEmpty(word))  
    25                     {
    26                         if ((word[0] >= 97 && word[0] <= 122) ) 
    27                         { 
    28                             wtrie.Insert(word); 
    29                         }
    30                         word = null;
    31                     }
    32                 }
    33             }
    34             if (!string.IsNullOrEmpty(word))  
    35             {
    36                 if ((word[0] >= 97 && word[0] <= 122) ) 
    37                 { 
    38                     wtrie.Insert(word); 
    39                 }
    40                 word = null;
    41             }
    42             this.linesnumber++;  //统计行数
    43             this.wordsnumber = wtrie.CountSum;  //统计单词数
    44             this.charactersnumber += dataline.Length;  //统计字符数
    45         }
    46     }

     运行结果:

    七、计算模块部分单元测试展示。 

    单元测试代码是根据可能出现的异常而设计出的,(部分单元测试代码见第八)。

    单元测试得到的测试覆盖率截图如下:

    八、计算模块部分异常处理说明。 

    1、单词以英文字母开头

     1 [TestMethod()]
     2         public void MainTest01()
     3         {
     4             string test;
     5             Program.Result trueres = new Program.Result();
     6             string reason;
     7             test = "123abcd";
     8             trueres.charactersnumber = 7;
     9             trueres.wordsnumber = 0;
    10             trueres.linesnumber = 1;
    11             reason = "测试用例1";
    12             UnitTest(test, trueres, reason);
    13 
    14         }

    123abcd不是一个单词。若错误会计算出单词数为1。

    2、单词以分隔符分割

     1 [TestMethod()]
     2         public void MainTest02()
     3         {
     4             string test;
     5             Program.Result trueres = new Program.Result();
     6             string reason;
     7             test = "abcd abcd@abcd";
     8             trueres.charactersnumber = 14;
     9             trueres.wordsnumber = 3;
    10             trueres.linesnumber = 1;
    11             reason = "测试用例2";
    12             UnitTest(test, trueres, reason);
    13         }

    单词以空格和非字母数字符号作分隔符分隔。若错误会计算出单词数为1。

    3、统计有效行数

     1 TestMethod()]
     2         public void MainTest03()
     3         {
     4             string test;
     5             Program.Result trueres = new Program.Result();
     6             string reason;
     7             test = "abcd\n\nabcd";
     8             trueres.charactersnumber = 8;
     9             trueres.wordsnumber = 2;
    10             trueres.linesnumber = 2;
    11             reason = "测试用例3";
    12             UnitTest(test, trueres, reason);
    13         }

    有效行数指任何包含非空白字符的行。测试设计了一个空白行,若错误会计算出行数为3。

    4、单词:字母后可跟数字

     1 [TestMethod()]
     2         public void MainTest04()
     3         {
     4             string test;
     5             Program.Result trueres = new Program.Result();
     6             string reason;
     7             test = "abcd123";
     8             trueres.charactersnumber = 7;
     9             trueres.wordsnumber = 1;
    10             trueres.linesnumber = 1;
    11             reason = "测试用例4";
    12             UnitTest(test, trueres, reason);
    13         }

    若错误则计算出单词个数不为1。

    九、结对的过程及结对照片。

    1、结对过程:

     我和与我结对的黄欣同学,先把项目需要完成的功能划分成几个模块,再一起填写psp表格并进行分工。我们分别完成各自分配的模块,中途遇到的问题一起讨论查资料解决,最后我们将代码合并起来。

     2、结对照片:

     

    十、解决项目的心路历程与收获,以及结对感受

    1、由于编程不熟悉,以及在实际的开发过程中遇到种种问题的阻挠,使得完成这个项目实际花费的时间远远大于预估计划的时间,并且一些功能也没有完善的很好,我感受到以后的学习还有很长的路需要去努力。

    2、结对感受:第一次结对完成一个项目,我的感受是1+1>2。因为在编程中,两个人除了独立完成自己那部分的功能任务,还能够在互审阶段会更容易发现对方自己不易察觉的问题,不仅如此,两人合作会使遇到的困难更容易被解决,学习中得到的进步也更大。而在这一次结对的实际操作中,让我对结对编程的理解更加深入了。

  • 相关阅读:
    EventBus
    Date 时间 日期 常用方法函数
    线程 Thread Handler
    MySQL-DoubleWrite
    MySQL各版本优化器变化
    MySQL优化器-条件过滤(condition_fanout_filter)
    PXC集群搭建
    mysql主从不一致--relay_log_recovery设置成0
    MySQL5.7-sql_mode
    根据ibd文件进行数据恢复或导入
  • 原文地址:https://www.cnblogs.com/TakeRabbit/p/10637605.html
Copyright © 2020-2023  润新知