zoukankan      html  css  js  c++  java
  • 2020软工结队项目作业

    一.教学班级和github地址

    项目 内容
    这个作业属于哪个课程 2020计算机学院软件工程(罗杰 任健)
    这个作业的要求在哪里 结队项目作业
    教学班级 006
    项目地址 结队项目作业

    二.PSP表格

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

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

    • Information Hiding,信息隐藏原则。在结构化函数的概念和面向对象的封装思想中,都深刻体现这一原则。在结构化函数层面,我们把实现具体内容的函数设置为private,把实现一个整体功能的函数设置为public,这样的话我们从外部调用一个模块的功能就会非常直观。面向对象方面,我们的整个工程分为了三个模块,模块之间的数据关系,调用依赖都是非常的独立。也就是说,每一次工作的时候,模块之间只会通信基本的控制信息和数据流,对各个模块具体的内容没有任何影响,这也符合了信息隐藏原则。
    • Interface Design ,接口设计。接口设计是实现程序的结构化和信息隐藏原则的最重要的方法,其将模型的方法抽象出来,作为一个函数或者类的方法供外部或自己调用。小到一个解决某个问题的程序,大到一个工程项目,都离不开接口设计。这次作业,我们设计了:
      • Core类,里面定义了方法addGeomrties(string input),外部只需要传入一个字符串就可以完成添加命令,因此这个函数可以在ui,命令行,控制台都方便的调用。方法intersect()只需要在添加集合体之后调用这个函数,core模块就会自动完成所有计算,不需要外界任何调用。
      • painter类,里面定义了方法paintEvent(QPainteEvent *event),外界不需要任何的调用,在我们的框架下,系统会自动根据窗口大小,集合数据自动重新画图,甚至不需要传入参数的过程。
      • Geometry对象,里面有一个枚举类包含了圆,直线,射线等所有不同的几何体,统一的定义了计算的接口完成计算,避免过多的分类讨论。
    • Loose Coupling,松耦合。松耦合是指减少程序各个功能模块之间的依赖程度。我们通过对直线类、圆类封装并提供相关的接口来实现对直线或者圆的初始化、某两个几何对象交点求解等功能;此外,我们还将总的求解方法封装在core中,实现整体的松耦合。

    四.计算模块接口的设计与实现过程

    设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?说明你的算法的关键(不必列出源代码),以及独到之处。(7')

    Point类:继承自pair,表示坐标点。

    Line类:表示直线、射线、线段,类别由属性type标识。包含计算直线交点的函数getIntersection_ll。

    class Line {
    
    public:
    
     double a;
    
     double b;
    
     double c;
    
     GType type;
    
     Point e; //方向向量
    
     Point p1; //输入点
    
     Point p2;
    
    
    
     Line();
    
     Line(Point source, Point target, GType type);
    
     int getIntersection_ll(set<Point>* intersections, Line l1, Line l2);
    
     void operator=(const Line& line);
    
    };
    
    
    

    Circle类:表示圆。包含计算两圆交点的函数getIntersection_cc。

    class Circle {
    
    public:
    
     Point c;
    
     double r;
    
    
    
     Circle();
    
     Circle(Point c, double r);
    
     void operator=(const Circle& circle);
    
     int getIntersection_cc(set<Point>* intersections, Circle c1, Circle c2);
    
    };
    

    Geometry结构体:包含一个Line或Circle类的实体,和一个指示类别的Gflag(取值为L或C)。这样就可以将Line和Circle的对象加入一个vector

    
    struct Geometry {
    
     GType Gflag;
    
     union {
    
     Line lObj;
    
     Circle cObj;
    
     };
    
    
    
     Geometry(Line l);
    
     Geometry(Circle c);
    
     void getObj(Line& obj);
    
     void getObj(Circle& obj);
    
     void operator=(const Geometry& g);
    
    };
    

    举例,将Line加入vector

    vector<Geometry> geomrties;
    
    Line *l;
    
    geomrties.push_back(*l);
    

    Core类:封装的计算核心模块,方便测试。

    class DLL3_API Core {
    
    public:
    
     set<Point> intersections;  //交点集合
    
     vector<Geometry> geomrties;  //几何体
    
     vector<string> errorInformations; //错误信息
    
     int isValid = 1;
    
     void addGeomrties(ifstream *fin); //从文件增加几何体
    
     void addGeomrtie(string text); //增加单个几何体
    
     int intersect();   //求geomrties内几何体的交点
    
     int addError(string input);  //增加错误信息
    
    };
    
    函数与类的关系:

    关键方法基本都封装在了类里面。先调用core.addGeomrties()函数增加几何体,再调用core.intersect()计算交点。addGeomrties函数是通过遍历文件调用若干addGeomrtie实现的,在测试阶段可以这样调用addGeomrtie("L 0 0 1 1")直接增加输入。intersect函数计算每两个几何体之间的交点,根据几何体类别分别调用getIntersection_ll、getIntersection_cc、getIntersection_cl。

    算法关键:

    圆与直线的交点算法与作业一相同,不再赘述。为了实现线段和射线的扩展,只需要把他们当作直线计算交点,然后判断交点是否在线段或者直线上。由于交点一定在线段或者射线延伸出来的直线上,只需判断交点的横坐标是否在线段端点之间,或者射线无限延伸的那一边。

    错误处理中判断“无限交点”这一项,判断直线类的几何体是否重合条件比较复杂。普通直线的重合判断公式是(frac{A1}{A2}=frac{B1}{B2}=frac{C1}{C2})。一种特殊情况是线段、射线所在直线重合时,由于自身长度有限可能并不重合。

    五.UML类图

    阅读有关 UML 的内容:https://en.wikipedia.org/wiki/Unified_Modeling_Language。画出 UML 图显示计算模块部分各个实体之间的关系(画一个图即可)。(2’)

    861585045485_.pic_hd.jpg

    六.性能改进

    计算模块接口部分的性能改进。记录在改进计算模块性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由VS 2015/2017的性能分析工具自动生成),并展示你程序中消耗最大的函数。(3')

    我们采用了(O(n^2))的交点求解算法。虽然求线段交点可以采用Bentley & Ottmann提出的基于扫描线的算法,将复杂度降到(O(nlogn)),但是我们的问题中有多种几何体,只优化线段与线段效果有些鸡肋。

    871585045487_.pic_hd.jpg

    881585045491_.pic_hd.jpg

    消耗最大的函数是getIntersection_ll,计算直线交点的函数,因为输入中只有直线类的几何体。在getIntersection_ll中最耗费时间的是set::insert函数。

    七.看 Design by Contract,Code Contract 的内容,描述这些做法的优缺点,说明你是如何把它们融入结对作业中的。

    • 契约式设计,是一种设计计算机软件的方法。这种方法要求软件设计这为软件组建定义正式的、精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。

      • 前置条件:为了调用函数,必须为真的条件,在其违反时,函数决不调用,传递好数据是调用者的责任。
      • 后置条件:函数保证能做到的事情,函数完成时的状态,函数有这一事实表示它会结束,不会无休止的循环
      • 不变式:从调用者的角度来看,该条件总是为真,在函数的内部处理过程中,不变项可以为变,但在函数结束后,控制返回调用者时,不变项必须为真。
    • 优缺点:

      • 优点:
        • 获得更优秀的设计
        • 提高代码的可靠性,有利于测试
        • 为不同模块约定其与其他模块的接口及其应该有的性质,方便模块之间的整合
        • 契约式设计可以明显降低调试的代价,能比较准确地定位错误
        • 支持复用
      • 缺点:
        • 契约式设计需要比较大的时间开销。
        • 小型项目中契约式设计似乎成为了一种限制,因为契约式设计较大的时间开销拖慢了整个小项目的进度。
    • 在本次结对项目中的运用:

      • 在本项目中主要通过注释的方法设计开发的计划,以便保证两个人的模块能正常的对接,一下是我们部分的约定注释。
      • 但是在实际运用中有的地方架构变化比较大,注释的方式可能存在过于死板的问题。

    八.计算模块部分单元测试展示

    计算模块部分单元测试展示。展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。并将单元测试得到的测试覆盖率截图,发表在博客中。要求总体覆盖率到 90% 以上,否则单元测试部分视作无效。(6')

    单元测试代码

    分别摘取了一个功能测试和一个异常测试,其中异常测试中测了判断输入格式的函数。

    //圆与直线相切
    
     TEST_METHOD(TestMethod9)
    
     {
    
      Core core;
    
      core.addGeomrtie("C 0 0 1");
    
      core.addGeomrtie("L 1 0 1 1");
    
      core.intersect();
    
      set<Point>::iterator it = core.intersections.begin();
    
      Assert::AreEqual((int)core.intersections.size(), 1);
    
      Assert::AreEqual(it->first, 1.0);
    
      Assert::AreEqual(it->second, 0.0);
    
     }
    
    //坐标越界
    
     TEST_METHOD(TestMethod13)
    
     {
    
      Assert::AreEqual(checkRange("L 0 0 100000 0"), 1);
    
      Assert::AreEqual(checkRange("L 0 0 -100000 0"), 1);
    
      Assert::AreEqual(checkRange("L 0 0 100001 0"), 1);
    
      Assert::AreEqual(checkRange("L 0 0 -100001 0"), 1);
    
     }
    

    测试思路

    功能测试:直线相交,直线平行,斜率无穷;两圆相离,嵌套,相切,相交;圆与直线相离,相切,相交;直线与线段相离;直线与射线相交,相离;圆内含线段,内含射线端点,圆与射线相离。

    异常测试:输入图形类别出错;输参数为小数;参数个数出错;圆的半径小于零;坐标越界;直线两点相同;两直线重合;两线段重合;(在同一直线上的)两线段不重合,两线段连接;两射线重合;(在同一直线上的)两射线不重合,两射线连接。

    覆盖率截图

    891585045494_.pic_hd.jpg

    九.计算模块部分异常处理说明

    • 我们定义了4种异常,如下图所示:

      181585033447_.pic_hd.jpg

      1. 输入的语句不符合语法:

        WechatIMG9.png

      2. 图形的数值不符合范围:

        WechatIMG10.png

      3. 图形两点存在重合:

      4. 两个几何体有无穷交点:

        WechatIMG11.png

      对每一种异常,我们都给其定义一个返回值

      其中两个几何体之间存在交点是最复杂的,需要考虑射线的方向,线段的端点。

    十.界面模块的详细设计过程。

    界面模块采用QT来开发。界面如下图所示,有一个窗口,三个部分:
    WechatIMG12.png

    • 最左边是功能控制面板。从上到下依次为控制按钮,图形选择器,输入文本框,状态反馈窗口,调整画图版。用户首先在输入文本输入想要添加的几何体,使用语法和控制台程序一样。然后点击添加按钮,该几何体就会出现在图形选择器界面中,同时在状态反馈窗口中提示用户输入是否合法,如果合法,则会在画板中更新。除此之外,用户可以通过删除按钮,导入文件按钮来删除几何体和从文件导入几何体。

      131585026862_.pic_hd.jpg

    • 中间的部分是画图版,每一次添加删除几何体,改变窗体大小都会重新绘制图像。画图内容包括坐标轴及其刻度,几何图形的轮廓,交点。

      WechatIMG14.png

    • 右边部分是我们的显示交点信息的界面,顶部显示交点的数量,下面显示交点的数值。

      WechatIMG15.png

    • 设计过程:这是我们第一次接触UI设计的领域,严格的说之前还有设计网页UI的经历,但不同的是,软件的UI需要从头到尾自己编码而不是简单的调用模版。我们先认真的分析了用户的使用习惯,得出了一下思路:

      1. 尽量简洁,避免多余的点击操作
      2. 把所有信息显示在一个平面上
      3. 实时提供反馈

      因此我们这样设计了这个软件,具体的实施过程中我们通过看样例,搜索网络资料,自己实验等方法,从无到有积累经验完成了ui的制作。

      WechatIMG16.png

    十一.界面模块与计算模块的对接。

    由于我们的core模块在本次调用中有两个部分,一个是错误处理函数,一个是core的主题对象,因此并不需要设计特别复杂的对接。

    WechatIMG17.png

    十二.描述结队的过程。

    • 我们一开始尝试过LIVE SHARE进行编程,但是在实际体验中发现这样对我们的效率并没有特别的提升,因此我们最终采用分工合作,主要是我来写前段部分,队友写后端部分

    • 我们在合作过程中遇到的最大的困难还是平台方面的困难,由于某些未知的原因,导致我可以运行生成的一些程序在我的队友的电脑上就会报错。我们花了大量的时间解决这样的问题,最后基本都解决了,但是还是有一些没有成功,只能采用我单独完成这部分的工作。

    十三.看教科书和其它参考书,网站中关于结对编程的章节,说明结对编程的优点和缺点。同时描述结对的每一个人的优点和缺点在哪里(要列出至少三个优点和一个缺点)。

    • 结对编程的优缺点:

      • 优点:
        1. 相互学习,每个人的代码都有很实用的技巧构思,看队友的代码可以学到很多东西。
        2. 相互监督,在一起工作的时候更有责任感,需要对自己开发的东西负责。
        3. 相互检查,有的问题一个人可能并不能发现,需要两个人一起检查才能发现。
      • 缺点:
        1. 两个人工作的进度和节奏可能存在一些差别,需要调整磨合适应。
    • 我与他的优缺点:

      她(gj)
      优点 比较注重代码细节;思考慎重,比较细心;能比较快速地查找到代码的bug。 比较细心,能够发程序的bug并提出优化方案。
      缺点 缺少耐心。 面对一些困难会耗费很多时间解决。

    十四.PSP回填,见二。

  • 相关阅读:
    均匀分布
    吉布斯采样(Gibbs采样)
    蒙特卡罗方法 Monte Carlo method
    马尔科夫链
    python 3 没有了xrange
    %matplotlib inline的含义
    MCMC采样和M-H采样
    pycharm 安装模块 use the correct version of 'pip' installed for your Python interpreter
    Pycharm安装第三方库时出现Read timed out的解决办法
    如何在Pycharm中添加新的模块(第三方包)
  • 原文地址:https://www.cnblogs.com/buaa17373407hjh/p/12560737.html
Copyright © 2011-2022 走看看