热门标签 | HotTags
当前位置:  开发笔记 > 程序员 > 正文

BUAA软工Week_4结对作业_最长英语单词链

项目内容这个作业属于哪个课程2022年北航敏捷软件工程这个作业的要求在哪里结对编程项目-最长单词链我在这个课程的目标是学习软件工程这个作业在哪个具体方面帮助我实现目


























项目内容
这个作业属于哪个课程2022 年北航敏捷软件工程
这个作业的要求在哪里结对编程项目-最长单词链
我在这个课程的目标是学习软件工程
这个作业在哪个具体方面帮助我实现目标学会与队友合作,了解结对编程,学习接口相关知识

1. 项目说明

  • 教学班级:周五班



  • 项目地址:https://github.com/ericaaaaaaaa/BUAA_SE_homework.git




2. 计划


























































































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

 


3. 教材阅读

看教科书和其它资料中关于 Information Hiding,Interface Design,Loose Coupling 的章节,说明你们在结对编程中是如何利用这些方法对接口进行设计的。


Information Hiding

要求提供一个稳定的接口,限制使用者调用的方法和范围,保护程序的其余部分不受实现的影响,同时也保护这个接口内的内容不被访问。在这次任务中,通过类core对各个函数和功能模块的封装组合,既保证了接口的统一,调用的便捷,也能够实现对这些模块使用的保护,可以提前对输入的参数进行测评、处理,再用核心计算单元进行计算。其中,在stage1中,我们在main函数中直接用inputProcess里的函数实现了对输入参数的分析、处理,再根据参数寻找word计算模块中对应的算法要求。在stage2中,通过使用core的封装,能够做到调用要求的四个函数,并在core中自动调用inputProcess参数处理,并根据分析自动调用word计算模块,或者报告异常情况。


Interface Design

要给调用者一个直接使用的接口,如此次作业中的GUI,命令行界面,通过图形化界面选择参数或者在命令行中输入参数进行接口调用,可以极大的方便调用者,同时,尽量减少接口的输入要求,在方便用户的设计思维下,需要被调用方更加全面的实现各种调用情况的应对,我们对可能存在的各种输入组合以及对应的措施如异常提示,各类功能的调用与结果输出进行了分析和实现。

如:


参数冲突表

表中记录了参数是否可以复合使用。(x 表示两个参数不能同时出现)























































































参数2 \ 参数1nwmchtr
nxxxxxxx
wxxxx   
mxxxxxxx
cxxxx   
hx x x  
tx x  x 
rx x   x

异常处理


参数


  • 存在非法参数



    • 未定义参数



      • 不只一个字母



      • 非字母或无字母







  • 参数非法使用



    • 具体参数的非法使用(见具体需求)



    • 冲突



    • 重复



    • 缺失



      • 无参数



      • 只有 -r, -h, -t 但没有功能指令








文件


  • 文件不存在



  • 没有给出文件名



  • 文件非法(不以 .txt 结尾)



  • 存在不只一个文件名




具体需求


-n


  • 功能

    统计该单词文本中共有多少条单词链,包含嵌套单词链



  • 输入

    文件的绝对或相对路径(以 .txt 结尾)。



  • 输出

    命令行输出

    一个数字 n ,代表单词链总数。

    之后的 n 行输出单词链(不同单词用空格分隔)。



  • 异常处理

    单词构成环路



  • 特殊情况

    没有单词链




Loose Coupling

减少各个模块之间的耦合性,能够使得可以几乎将所有的模块独立,并且能够在对模块的实现方法了解很少的基础上实现调用、组合,也可以方便模块正确性测试。

在这次作业中,分为inputProcess,word,core,exception四大板块,其中inputProcess实现了两组输入处理模式,一个是针对阶段一中命令行的输入需求对参数输入进行处理,另一组是针对GUI中能够传入的参数进行处理;word则是计算关键,分为N,M,W_noR,W_R,C_noR,C_R几大功能。异常包包含了各种异常错误类型,core则实现对外统一封装。


附加题小组交换core

本组与周子颖(19373132)、王宇欣(19373349)交换了 dll 模块,并分别进行了测试,测试方式为:



  • 本组单元测试模块 + 对方组的 dll



  • 本组的 GUI + 对方组的 dll



  • 本组的 dll + 对方组测试模块



  • (由于在互换时对方组没有设计 GUI,故无法实现本组的 dll + 对方组 GUI)



在这次的结对编程中,我们保证了core的接口定义,此外要求输入的result是一个提前开了20000个指针类型空间的指针,严格要求inputLen和input所包含的字符串数量相同。

与别组交换core进行测试的时候,也同样要遵循该组对输入参数的规定。例如在此次交换的小组,除了课程组中参数类型规定,该组的契约要求了输入的result要是一个提前开了20000个指针类型空间的指针,输入的char** input只能包含无重复输入的全小写英文单词,输入参数head,tail只能输入小写英文字母。这样就要求我们在调用时,提前将所有的单词串做去重处理,并将不符合要求的字符单词处理了,以及在输入head和tail时保证该参数的正确性。

除了以上的参数要求,互相在交换调用的时候不在关注其实现的过程,并且也只在测试程序中调用接口函数即可,如果出现问题,则可以将该模块单独拎出去进行测试。

在交换模块中,发现对方小组:



  1. 对于无链的情况("ab", "cbc", "dcd", "ede", "faf", "gfg", "hgh")处理出现错误(图一,左图为我们dll,右图为对方dll)



  2. 对于五点全向图测试样例瞬间卡退崩溃



  3. 出现异常情况时,dll没有提示异常信息,也没有处理异常,而是将异常抛出,需要外面调用者自己catch处理(个人认为是一个设计缺陷)(图二)



 

 

 


4. 模块接口设计与实现

-n

算法设计:采用 DFS 的方式实现,每次求出以某一特定字母开头的全部可能单词链。


无环路

数据结构alphatet中每一格存首尾相同的单词list组

 


判断环路


算法设计

采用深度搜索,将首尾相同的单词都视作同一个边,用CycleFind记录每轮递归找到的点,同时找到的点都放入AllFind中,如下如分析,如果在单词深度搜索中没有找到导致环路的点,那么这一轮所有出现过的点都不用再分析了,因为假设再用它为开头找环,如果能够找到环,则在它之前的那一轮循环中也能找到环,这样就出现矛盾,因此用AllFind排除一些重复的点,并且将未知单词个数简化到最多26个点。

 


-w


算法设计

和环路算法数据结构相同,同样视首尾相同的单词为同一条线,换成迪杰斯特拉算法找所有源的最大长度路径,由于无环,首先排除入度不为0的字母,循环遍历只出不进的字母,每一轮找到离该源点最大路径的点,经过一次松弛,记录前项点,其中避开a---a格式的点,保证除了初始点,前项点始终与自己不同,循环所有点后,再进行下一个单源点寻找。在计算最长路径的时候,需要通过前项点寻找路径,同时,假设找到的点为a,如果alphabet中存在a---a格式的点,则需要将路径再添加一次权重,如果长度超过现有最大值则更新。

只有-t时,反转alphabet[colomn][row]colomn\row去寻找

权重为1


-c


算法设计

上述算法中权重为单词长度


-m


算法设计

上述算法中寻找路径时跳过对a---a格式的点的判断


有环路


-w & -c


算法设计

在有环路的情况下,统一采用 DFS 的方式进行检索,每在单词链中添加一个单词即将其标记为 dirty,选取最长的单词链保存。


性能改进

由于 -c 要求选出字符长度最长的单词链,因此在输入时可根据单词长度对其排序,每次从最长单词开始遍历,可以减少对于单词图的遍历次数,获得一定的性能提升。


5. UML 图

 

 

UML、函数流程混杂图(其中绿色为stage1,红色为stage2)

 


6. 模块接口部分性能改进

在测试中-w和-c测试量相同,其中性能测试样例包含四点全向图,多链,固定首尾。分析函数性能,Core::gen_chain_wordCore::gen_chain_char 所封装的 FunctionC_RFunctionC_R 占据了极大的比例。其中 FunctionC_R 更多,是因为该函数需要获取单词的长度作为权重,在查单词长度时导致了这一消耗。



  • 改进思路1:通过加入对点的判断,减少不必要的点的函数递归调用



  • 改进思路2:有参数 -c 时先对单词长度进行排序,再执行算法



  • 改进思路3:引入编译优化



 

 

对于-noR,可以通过不再读入两个以上的同样首尾的单词(a---a格式可以读入两个)来降低其读入的时间开销。


7. Design by Contract, Code Contract

契约式编程是一种设计方法,为传统的抽象数据类型增加了先验条件、后验条件和不变式。通过增加contract实现对函数、方法、接口调用的参数规范,从语法、语义上对调用接口进行了封装保护。比如.NET的代码协议中,contract可以在运行时提供自动测试工具,过滤掉不满足先决条件的测试参数,或在不运行程序时自动检查隐式契约如空指针或越界等情况,或调用程序员的显式契约。

契约式编程对程序语言要求很高,需要有机制来验证契约的成立,可以使用断言机制但是仍有语言不包含这些机制,而且契约的机制并没有统一标准,因此存在语言与语言之间、项目之间契约模块的不同。

契约的思想要求调用者一方根据接口的要求来调用,被调用者则需满足测试要求条件之内的正确性。这保证了双方地位的平等,与以往被调用者需要考虑全所有的情况并给出相应的应对来保证准确性更加安全,可靠,同时也能够使得程序测试或者调用时更加高效,有序。

在这次的结对编程中,我们保证了core的接口定义,参数要求范围内程序运行的正确性,生成了dll模块。我们要求了输入的result要是一个提前开了20000个指针类型空间的指针,严格要求inputLen和input所包含的字符串数量相同。

与别组交换core进行测试的时候,也同样要遵循该组对输入参数的规定。例如在此次交换的小组,除了课程组中原本的参数类型规定,该组的契约要求了输入的result要是一个提前开了20000个指针类型空间的指针,输入的char** input只能包含无重复输入的全小写英文单词,输入参数head,tail只能输入小写英文字母。这样就要求我们在调用时,提前将所有的单词串做去重处理,并将不符合要求的字符单词处理了,以及在输入head和tail时保证该参数的正确性。


8. 单元测试

单元测试覆盖率如下:

 

 


8.1 测试函数说明

init(char** inputw,int inLenw):将测试用例导入;

void check(int refLen,char *refAns[]):将参考结果导入,如果refLen是-1,则默认跳过assert核对环节;

axxxxa ax 的词组





  • 多链



    • 是否有会被重复使用到的单词如 "ab"之于da ca







  • 有环




  • W/C



    • -r 带环



    • -h 有参数,以该单词为首,是否存在链



    • -t 有参数,以该单词为首,是否存在链



    • 样例中存在一个以 word 为标准的最长链和一个以 char 为标准的最长链



    -n, -m, -w_noR, -c_noR



    • 有环





  • -h, -t



    • 参数不是单词字母





  • result长度超过 20000



  • -h-t,用户在勾选后可以在右方输入框内填入首字母 / 尾字母,如图。(若不勾选 -h-t,窗口中的内容视为无效)

     


    输出


    窗口输出

    用户点击“运行“后,可将运行结果输出至下方文本框中。

     


    导出文本

    点击“导出文本”,弹出保存文件窗口,可以将输出(下方文本框的内容)保存至用户选定的位置(覆盖 / 新建文本文件)。

     


    10.5 加入异常处理逻辑


    输入异常



    1. 当导入文件不以 .txt 结尾时,在输出框中报出异常,如图。

       



    2. 当导入文件中的单词数量(包括重复)大于 20000 时,会报出异常,如图

       




    参数异常


    参数冲突

    当发生参数冲突时,点击”运行“会在下方文本框中报出相应错误信息,如图:

    参数不能同时出现

     

    没有功能性参数(-n, -w, -c, -m

     


    参数长度不合法

    -h-t 中传入参数长度不为 1 时,会在下方输出框中报出该错误。

     

     


    参数内容不合法

    当参数不是合法的英文字母时,会在下方输出框中报错,如图。

     


    运行异常


    代码存在环路(但无 -r 参数)

     


    10.6 加入其它逻辑

    由于运行需要一定时间,在运行时输入文本框如果改变,可能对运行结果的正确性产生一定的影响,因此在点击”运行“后,会先将输入文本框设为只读,并在运行结束后恢复。


    11. 模块连接

    用 dll 连接图形界面与计算核心。


    11.1 生成 dll

    用类 Core 封装接口。



    1. 提取接口

      修改源文件中的函数,将其改为适应给定接口的函数:



      • int gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool enable_loop)



      • int gen_chains_all(char* words[], int len, char* result[])



      • int gen_chain_word_unique(char* words[], int len, char* result[])



      • int gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop)





    2. 建立 Core 类

      建立 Core 类,并将上述接口封装入 Core 类中。

      其中



      • Core.cpp 中给出各接口的实现

        HMODULE hModule = LoadLibrary(_T("core.dll"));, 动态库 dllmain 中定义的一个入口,一个是functionC C = (functionC)GetProcAddress(hModule,"gen_chain_char");,functionC 是参数组的指针类型,这两个其中一个得到了 NULL 的值,都会导致 dll 调用失败



      • HMODULE hModule

        失败的原因可能是是 vs 平台选择错误或者传入地址填写错误,或与 Unicode、LPCSTR、string 等格式类型有关



      • GetProcAddress



        • 返回 NULL:error = 127



        • dll 生成函数名已经出现错误了,不是源文件中的 那个函数名。注:查看 dll 函数名工具:Dependency Walker






      11.3 与 GUI 按键连接

      main 函数中的 QWidget::connect 函数可以设置按键对应的响应函数,编写方式如下:(只保留框架)

      // 运行代码
      QWidget::connect(createUi.pushButton, &QPushButton::clicked, [&]{
      // 获取输入
      words = ...;
      result = ...;
      wordCount = ;
      // 运行代码
      if (...) {
      length = N(words, wordCount, result);
      // 判断返回值的合法性
      } else if () {
      ...
      }
      // 输出结果
      ...
      }

      到此,已实现了 GUI 和计算模块的连接。


      12. 结对过程

      结对采用了线上与线下结合的方式,截图 & 照片如下:

       

       

       


      13. 结对优缺点

      先夸我的队友:思路清晰,很好合作,自律负责

      优点:在结对编程的时候,能够将题目考虑得更加全面,比如我队友,第一次见面进行结对编程的时候,队友认真的带我捋了一遍所有的功能、异常的可能,经过讨论,可以极大的单人思考时会降低疏漏的点,此外就是编程的时候一写、一审可以提高单人编程准确性,虽然期间会出现两个人同时忽略的bug,但是会减少;也能够在一些逻辑简单的情况下提高编程速度,因为两个人的想法一致的时候,编程速度是由想得最快的那个人的决定的。能够让我学习到一些新的好的习惯,比如队友在遇到不熟悉的用法时,会查一查然后果断开一个小的demo直接测试,而我可能倾向于慢吞吞的上网查,然后还是不确定用法和相关原因,并且队友擅长markdown记录,当分析题目的时候,会有条理的对要求的点进行梳理,排版清晰,覆盖全面的进行总结,而我则更习惯读题读题,拿草稿纸画一画大概有哪些组合,最后真正编程的时候才罗列情况。(PS:DDL的压力也减少了

      缺点:结对编程需要两个人有共同的充足的时间,首先有人一起编程会改变之前我们独自编程的习惯,去适应并进入结对编程状态需要时间,此外在结对编程时多出来的互动和讨论可能也会导致编程思路中断,在困难的点上我倾向于自己静下来想一想,也更倾向于自己debug,这个习惯导致我在结对前期的时候根本没法去写一些计算模块,然而我的队友是很好的patner,我的锅...在后期更加适应了两人合作的编程模式后,我们在测试阶段既体验到两人思路的完善,也能提高代码验证的效率。


      14. 实际花费时间

      独立完成













































































































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


    推荐阅读
    • 前端微服务二
      为了解决庞大的一整块后端服务带来的变更与扩展方面的限制,出现了微服务架构(Microservices):微服务是面向服务架构(SOA)的一种变体,把应用程序设计成一系列松耦合的细粒 ... [详细]
    • 开发笔记:(源码开放) React + webpack3 多页面应用 及 常见问题解答
      本文由编程笔记#小编为大家整理,主要介绍了(源码开放)React+webpack3多页面应用及常见问题解答相关的知识,希望对你有一定的参考价值。 ... [详细]
    • XShell连接不了虚拟机
      本机安装好虚拟机和centeros;使用xshell连接:linuxCouldnotconnectto'127.0.0.1'(por ... [详细]
    • PIMPL 是 C++ 中的一个编程技巧,意思为指向实现的指针。具体操作是把类的实现细节放到一个单独的类中,并用一个指针进行访问 ... [详细]
    • redis-cli后面加上--raw解决中文显示问题 redis-cli-h127.0.0.1-p端口-a密码  --raw不带--raw参数:redis-cli-h10.168. ... [详细]
    • java怎么实现非下降数组
      今天小编给大家分享一下java怎么实现非下降数组的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给 ... [详细]
    • 局限性_Scrum框架的局限性
      篇首语:本文由编程笔记#小编为大家整理,主要介绍了Scrum框架的局限性相关的知识,希望对你有一定的参考价值。在很多工作坊的讨论中, ... [详细]
    • 事务是通过MULTI命令开始的,在非事务状态下客户端发送的命令会被立刻执行,而在事务状态下,除了EXECWATCHDISCARD这几个命令外,redis会将命令保留在事务队列里。 ... [详细]
    • MyBatis模糊查询和多条件查询一、ISmbmsUserDao层根据姓名模糊查询publicListgetUser();多条件查询publicList ... [详细]
    • 开发笔记:sql盲注之报错注入(附自动化脚本)
      篇首语:本文由编程笔记#小编为大家整理,主要介绍了sql盲注之报错注入(附自动化脚本)相关的知识,希望对你有一定的参考价值。 ... [详细]
    • 看下面的代码:window.onload=someFunction;很多时候我看到使用这种代码,甚至我使用相同的代码.但是, ... [详细]
    • 导读:今天编程笔记来给各位分享关于php动态扩展怎么加载的相关内容,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: ... [详细]
    • rtemsapi用户指南Elixir代表了相对较新的编程语言,面向更广泛的受众。它于2011年发布,此后一直在开发中。他的主要特征是取消功能范式 ... [详细]
    • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了将JSON数组反序列化为强类型的.NET对象相关的知识,希望对你有一定的参考价值。 ... [详细]
    • 载波|等份_NR SRS时频域位置
      篇首语:本文由编程笔记#小编为大家整理,主要介绍了NRSRS时频域位置相关的知识,希望对你有一定的参考价值。微信同步更新欢迎关注同名modem协议笔记S ... [详细]
    author-avatar
    平凡简单
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有