第四次作业

第四次个人作业


(1).介绍

作业要求地址 地址
GitHub项目地址 项目
结对伙伴博客 zofun的博客
本人学号 201731062415
结对伙伴 唐财伟

(2).PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 20
Estimate 估计这个任务需要多少时间 30 30
Development 开发 700 720
Analysis 需求分析 (包括学习新技术) 120 120
Design Spec 生成设计文档 40 30
Design Review 设计复审 (和同事审核设计文档) 60 30
Coding Standard 代码规范 (为目前的开发制定合适的规范) 30 30
Design 具体设计 120 120
Coding 具体编码 300 480
Code Review 代码复审 60 60
Test 测试(自我测试,修改代码,提交修改) 60 60
Reporting 报告 60 120
Test Report 测试报告 30 60
Size Measurement 计算工作量 20 30
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 30 45
合计 1690 1955

(3).接口设计与实现

  1. 分析
    本次作业的话,大致可以分为以下几个基础功能:
  • 统计字符
  • 统计单词总数
  • 统计行数
  • 统计文件中各单词的出现次数,最终只输出频率最高的10个
  1. 思路
    我们希望利用一种模式,能够输入的文本和利用该文本进行的一系列操作解耦,让他们脱离开来,于是我们单纯的考虑到了职责链模式,该模式可以将请求的发起者和请求的处理者解耦,我们在仔细分析了该模式在本次作业中的可行性后,发现职责链模式确实可以来解决本次问题,于是我们便开始了代码的思考。
  2. 实现过程
    我们设计了总共8个类来实现所有的功能,具体如下:
  • Handler类:作为抽象处理者,定义了抽象的处理方法process
  • Program类:作为client(客户)类,向链中的对象提出请求
  • Context,AnalyzeProcess,WordCount,ResultOutPutProcess,InputProcess类,作为具体的处理者。
  • FileOutPutProcess,FileInputProcess:作为具体实现处理者的类,这两个类作为文件输入和输出。
    大概的类图如下:
    avatar

关键代码:

  • 统计字符数:
public void countChar(Context context)
{
    int count = 0;
           
    foreach (char countchar in context.FileInfo)
    {
        if(countchar<128 && countchar >= 0)
        {
            count++;
        }
    }
    context.BaseInfo.Add("characters", count);

}

  • 统计每个单词出现次数
private void countWords(Context context)
{
    string[] words = Regex.Split(context.FileInfo, @"\W+");
    context.BaseInfo.Add("words", 0);
    foreach (string word in words)
    {
        if (word.Length >= 4)
        {
            context.BaseInfo["words"]++;
        } 
        if(word != "")
        {
            if (context.WordCount.ContainsKey(word))
            {
                context.WordCount[word]++;
            }
            else
            {
                context.WordCount[word] = 1;
            }
        }
                      
    }
}
  • 统计行数
private void countLines(Context context)
{
    mch = Regex.Matches(context.FileInfo, "\n");
    context.BaseInfo.Add("lines", mch.Count+1);
}
  • 统计词组
public void countWordGroup(Context context ,int m)
{
    string[] words = Regex.Split(context.FileInfo, @"\W+");
    for (int i = 0; i < words.Length - m; i++)
    {
        string wordGroup = null;
        for (int j = i; j < i+m; j++)
        {
            wordGroup = wordGroup+words[j]+" ";
        }
        if (context.GroupCount.ContainsKey(wordGroup))
        {
            context.GroupCount[wordGroup]++;
        }
        else
        {
            context.GroupCount[wordGroup] = 1;
        }
    }
}

  • 输出表达式(展示一部分)
sw.WriteLine("单词统计信息:");
//按字典序排序
context.WordCount = context.WordCount.OrderByDescending(o => o.Value).ThenBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value);
int count = 0;
foreach (KeyValuePair<string, int> entry in context.WordCount)
{
    sw.WriteLine("{0}:{1}", entry.Key.ToLower(), entry.Value);
    count++;
    if ((count == n) && n != -1)
    {
        break;
    }
}

(4).代码复审过程

  • 代码规范
    我们采用了该代码规范
  • 代码复审
    我的某些功能实现的并不是很严谨,在我自己运行时没发现,在同伴的审查下,某些小缺陷一下就暴露出来了,得到了及时的更正,所以更多时候是我们共同审核我的部分(狗头)。。

(5).计算性能

  • 运行过程:
    avatar
    avatar
  • 性能
    avatar
    可以看到,大部分的资源都耗费在了WordCount上,但是程序总的耗费时间很短,因此修改的需求并不是很大。

(6).单元测试

  • 统计字符模块的单元测试
  1. 编写单元测试代码
    uOXUFP.png
  2. 查看测试结果
    uOvran.png
  • 统计单词模块的单元测试
  1. 编写测试代码
    uXPBlt.png
  2. 测试结果
    uXPWfs.png
  • 统计词组模块的单元测试
  1. 编写测试代码
    uXAaHf.png
  2. 测试结果
    uXAygs.png

(7).异常处理

  • 读取文件时的异常处理代码
try
    {
        text = File.ReadAllText(path);
        context.FileInfo = text;
        //Console.WriteLine("文本内容如下" + context.FileInfo);
        //完成文本内容的读取后,交由下一个处理
        getNextHandler().process(context);
    }
catch(Exception e)
{
    Console.WriteLine("请输入正确的文件路径!");
}
  • 输出文件异常处理代码:
try
{
    sw.WriteLine("文本基础信息如下(其中words统计了小于等于4个字母的)");
    foreach (KeyValuePair<string, int> entry in context.BaseInfo)
    {
        sw.WriteLine("{0}:{1}", entry.Key, entry.Value);
    }
    sw.WriteLine("单词统计信息:");
    //按字典序排序
    context.WordCount = context.WordCount.OrderByDescending(o => o.Value).ThenBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value);
    int count = 0;
    foreach (KeyValuePair<string, int> entry in context.WordCount)
    {
        sw.WriteLine("{0}:{1}", entry.Key.ToLower(), entry.Value);
        count++;
        if ((count == n) && n != -1)
        {
            break;
        }
    }
    sw.WriteLine("词组统计信息:");
    context.WordCount = context.WordCount.OrderByDescending(o => o.Value).ThenBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value);
    foreach (KeyValuePair<string, int> entry in context.GroupCount)
    {
        sw.WriteLine("{0}:{1}", entry.Key.ToLower(), entry.Value);
    }
}
catch (Exception e)
{
    Console.WriteLine("输出文件错误!");
}
finally
{
    sw.Flush();
    sw.Close();
}


(8).结对过程

因为是室友,合作了那么多次,所以没有经过考虑,我们便结对了。
结对照片
avatar


(9).附加功能

avatar
avatar


(10).总结

对于我来说,这次结对编程的效果绝对是1+1>2的,如果只是我一个人的话,我不会想到用什么模式来实现这样的问题,在我的考虑里,一个类可能就能解决掉所有的功能,但是这样的写法在以后肯定是会出现大问题的,我知道,所以这次的结对给我了一种新的考虑问题的方式。

posted @ 2019-10-13 22:12  宥ly  阅读(155)  评论(2编辑  收藏  举报