• 结对项目作业


    1. 项目地址

    项目 内容
    课程 软件工程
    作业 结对项目作业
    教学班级 005
    项目地址 https://github.com/huangjihui511/IntersectProject2

    2. PSP 表格

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

    3. 接口设计

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

    信息隐蔽是开发整体程序结构时使用的法则,即将每个程序的成分隐蔽或封装在一个单一的设计模块中,定义每一个模块时尽可能少地显露其内部的处理。信息隐蔽原则对提高软件的可修改性、可测试性和可移植性都有重要的作用。

    以下列举了一些信息隐藏原则的应用。
    1 多层设计中的层与层之间加入接口层;
    2 所有类与类之间都通过接口类访问;
    3 类的所有数据成员都是private,所有访问都是通过访问函数实现的;

    藕合度是度量一个代码单元在使用时与其他单元的关系。松耦合是一个单元无需其他代码单元特别的配合而可以使用。

    我们运用了单例模式的思想封装出一个core类,相当于计算处理器,用vector存储几何体,拥有计算交点的方法。这样后端就被完整封装,和ui之间的耦合很松散,只需要在ui中创建core对象。

    我们写了一个Geometry结构体用来存储直线和圆的实例(为了在core中形成一个几何体容器,不区分直线和圆的具体类别),使用void getObj(Circle& obj)或void getObj(Line& obj)的方法根据传入参数的类型得到对应实例,体现了信息的隐藏。

    但是我们Line,Circle类的属性是public的,这一点不够谨慎,没有充分隐藏信息。

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

    设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?说明你的算法的关键(不必列出源代码),以及独到之处。(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})。一种特殊情况是线段、射线所在直线重合时,由于自身长度有限可能并不重合。

    5. UML图

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

    6. 性能改进

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

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

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

    7. Design by Contract,Code Contract

    看 Design by Contract,Code Contract 的内容:
    http://en.wikipedia.org/wiki/Design_by_contract
    http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx
    描述这些做法的优缺点,说明你是如何把它们融入结对作业中的。(5')

    Code Contract规定软件设计人员应为软件组件定义正式,精确和可验证的接口规范,该规范应使用前提条件,后置条件和不变式来扩展抽象数据类型的普通定义。根据对商业合同的条件和义务的概念隐喻,这些规范被称为“contract”(合同)。

    优点是

    定义了精确的接口规范,从而使得程序移植性好,降低出错的机率。

    缺点是

    一些简单的函数也使用接口规范,会增加开发的负担。

    我们对接口返回值的规定,用注释标注在了函数定义之前。由于大多数函数比较简单,只写了个别的函数,比如检查错误的函数返回值的含义。

    8. 单元测试

    计算模块部分单元测试展示。展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。并将单元测试得到的测试覆盖率截图,发表在博客中。要求总体覆盖率到 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);
    		}
    

    测试思路

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

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

    覆盖率截图

    9. 异常处理说明

    计算模块部分异常处理说明。在博客中详细介绍每种异常的设计目标。每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景。(5')

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

      181585033447_.pic_hd.jpg

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

        WechatIMG9.png

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

        WechatIMG10.png

      3. 图形两点存在重合:

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

        WechatIMG11.png

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

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

    10. 界面模块

    界面模块的详细设计过程。在博客中详细介绍界面模块是如何设计的,并写一些必要的代码说明解释实现过程。(5')

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

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

      131585026862_.pic_hd.jpg

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

      WechatIMG14.png

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

      WechatIMG15.png

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

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

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

      WechatIMG16.png

    11. 界面模块与计算模块的对接

    详细地描述 UI 模块的设计与两个模块的对接,并在博客中截图实现的功能。(4')

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

    WechatIMG17.png

    12. 结对的过程

    描述结对的过程,提供两人在讨论的结对图像资料(比如 Live Share 的截图)。关于如何远程进行结对参见作业最后的注意事项。(1')

    尝试过Code Share,最后觉得微信交流更有效率。

    13. 结对编程的优点和缺点

    看教科书和其它参考书,网站中关于结对编程的章节,例如:http://www.cnblogs.com/xinz/archive/2011/08/07/2130332.html ,说明结对编程的优点和缺点。同时描述结对的每一个人的优点和缺点在哪里(要列出至少三个优点和一个缺点)。(5')

    结对编程的优点:能得到更高的投入产出比

    • 开发层次,能提供更好的设计及质量和代码质量,有更强解决问题的能力
    • 对开发人员自身,能带来更多信心,以及高质量产出的满足感
    • 在心里上,结对的人不好意思开小差
    • 再企业管理层次,结对能更有效交流,相互学习和传递经验。

    结对编程的缺点:

    • 能力较强者和较弱者需要磨合,强者不可避免地要多付出一些

    我的优缺点:细心;思路比较周全;对ui的效果有些执着;缺点是对编译环境引发的问题一无所知

    队友的优缺点:效率高!解决问题的能力强!代码结构好!暂时没有缺点

  • 相关阅读:
    深入浅出JSONP--解决ajax跨域问题
    Apache与Tomcat的区别
    项目终于接近尾声了
    交互设计[小插曲]--网站UI配色
    使用 Jasmine 进行测试驱动的 JavaScript 开发
    javascript单元测试
    MySQL查询当前数据库中所有记录不为空的表
    cannot be resolved to a type的错误
    oracle 表空数据导出dmp ,空表导出失败
    Iterable<E> Iterator<E>
  • 原文地址:https://www.cnblogs.com/mollygarden/p/12560856.html
Copyright © 2020-2023  润新知