zoukankan      html  css  js  c++  java
  • BUAA软件工程_结对编程

    1.写在前面

    项目 内容
    所属课程 2020春季计算机学院软件工程(罗杰 任健) (北航)
    作业要求 结对项目作业
    课程目标 培养软件开发能力
    本作业对实现目标的具体作用 培养结对编程开发项目的能力
    教学班级 006
    github项目地址 IntersectDualProj
    结对伙伴博客 17373124

    2.PSP表格记录

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

    3.接口设计学习

    • 信息隐藏(Information Hiding)原则

      In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change)

      信息隐藏是指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。因此,我们设计的计算类中所有属性都是private,所有访问都是通过访问函数实现的。所有容器访问改为迭代器访问。

    • 接口设计(Interface Design)

      参考了一些相关的博客,详见接口设计六大原则

      单一责任原则(Single Responsibility Principle, 简称SRP)

      There should never be more than one reason for a class to change

      考虑到这一原则,我们封装了图形对象的相关类、计算交点的类,异常处理的类等,将各个功能分离。

      Calculator类中,我们将计算分为了多个层次,分写了多个成员函数。分别对点在线上、点在圆内、平行判断、交点计算(线与线、线与圆、圆与圆、汇总计算)进行各模块的编写

    • 松耦合(Loose Coupling)

      In computing and systems design a loosely coupled system is one in which each of its components has, or makes use of,little or no knowledge of the definitions of other separate components.

      我们的接口设计遵从高内聚,低耦合的设计思路。在附加题部分,我与我的队友对于接口的设计讨论了很久。我们这次的计算核心模块和GUI以及命令行的对接,增加了中间转换层,来实现系统的核心模块和用户交互层的彻底解耦。下面的代码就是我们核心模块面向GUI和cmd的中间层设计。内部计算实现彻底隐藏,只注明外部调用接口规范,这个内容会在GUI设计部分详细说明。

      // IOinterface.h
      IMPORT_DLL int guiProcess(std::vector<std::pair<double, double>>* points, std::string msg);//计算模块与GUI的接口
      IMPORT_DLL void cmdProcess(int argc, char* argv[]);//计算模块与命令行的接口
      

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

    我们这次的项目是在上一次的个人项目框架上进行扩展的。

    在其基础上,我们做了如下改进:

    将原有的Line和Circle结构体(原来的Line和Circle只存储数据,故采用结构体)封装为类。为Line类添加type属性,分别可表示直线,射线,线段。由于这三种线的交点计算步骤较为统一,故在较少改动框架的基础上,我们将这三种线融为一个类型。除此之外,运用叉乘计算,实现了pOnLine(Point p, Line l)方法来判断点是否在线上。

    具体设计如下:

    • 一共六个类

      classP

    • 类与类之间的关系

      graph LR A[Point] --> B[Line] A --> C[Circle] A --> D[Calcalator] B --> D C --> D D --> E[IOinterface] D --> F[Exception] E --> F E --> G[GUI调用] E --> H[cmd调用]
    • 关键思路依然是几何对象两两求解交点,其中通过一些预判剪枝优化。由于交点计算的关键函数实现都在上一次作业博客中说明了,这次不做特别阐述,着重说明新增功能的拓展。

    • Calculator 类

      • 这是由于新增射线和线段需要做比较多改进的地方

      • 其中Line与Line的交点计算的预判(用到叉乘的方法) 参见 博客,无法预判的内容比如射线,则先计算交点,再通过pOnLine(Point p, Line l)方法来判断点是否在线上。

      • 直线和射线与圆的问题处理,计划先算出交点,再判断点是否在line上

      • 线段与圆关系进行预判,比如线段两点都在圆内时必不存在交点。一定程度的降低时间复杂度

      • 圆与圆的交点无需改动

        class Calculator {
        public:
        	Calculator();
        	inline double xmult(Point v1, Point v2);
        	double xmult(Point o, Point a, Point b);
        	//判断点是否在line上 在line上则return true
        	bool pOnLine(Point p, Line l);
        	// 圆内 return true;  相切/相离  return false;
        	bool pInCircle(Point p, Circle c);
        	bool isParallel(Line l1, Line l2);//判断两线是否平行 (并捕捉 重叠的异常)	 
        	int haveIntersection(Line l1, Line l2, set<Point>& nodeSet);
        	int haveIntersection(Circle c, Line l, set<Point>& nodeSet);
        	int haveIntersection(Circle c1, Circle c2, set<Point>& nodeSet);
        	//计算全部交点
        	int countAllinsect(vector<Line> lVec, vector<Circle> cVec, set<Point> &nodeSet);
        };
          
        
        
    • Line类

      新增射线和线段的功能

      // 'L' -> line;
      // 'R' -> radio;
      // 'S' -> segment;
      class Line
      {
      public:
      	Line();
      	Line(char newType, double x1, double y1, double x2, double y2);
      	char getType();
      	double getA();
      	double getB();
      	double getC();
        double getSlope();
      	Point  getP1();
      	Point  getP2();
      
      private:
      	char type;
      	Point p1;
      	Point p2;
      	double A;
      	double B;
      	double C;
        double slope;
      };
      

    5.画出 UML 图显示计算模块部分各个实体之间的关系

    uml

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

    • 在算法((O(n^{2})))大体思路没有改变的情况下,性能的较大提升很难实现。这里记录了几个小修改:
    1. 直线平行判断优化,我们将直线的slope属性存储在直线class中,判断平行时直接调用判断相等,而不用多次计算斜率
    2. 部分小函数宏定义优化,对于double相等以及大小比较的小型但是多次调用的函数,我们将其设定为宏定义,减少函数调用的时间消耗
    3. 以及一些小的修改,根据函数调用的局部性原理,将分支语句中更多调用的语句提前之类
    4. 学习了助教发的sweep line提示文档,对比其中内容和自行编写的代码,由于sweep line似乎只能优化线段的内容,作业时间有限,也就没有做这个部分的优化。
    • 最终性能分析图片如下:

      占用性能最多的函数还是求直线交点函数,该函数中交点集合的插入部分是占用CPU最多的数据操作。这部分由于set的红黑树原理决定的,无法改善。

      21334

    7. Design by Contract,Code Contract 的内容学习

    契约式设计和代码协定,这种方法要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。这与我在OO课程中接触到的jml类似。

    • 优点

      • 在项目开发初期,可对全局进行把控
      • 明确接口的功能,消除二义性
      • 有利于分工合作
      • 利于使用者对代码的理解
    • 缺点

      • 效率低,代码量大
      • 项目初期很难预知全部需求与问题,契约会被迫修改
    • 应用

      这个方法是很有利于多人协作开发的。虽然我们没有严格按照规范来执行这个方法,但我们也在结对编程中运用到了其思想。在初期,我和我的队友对设计进行了讨论,并确定了设计文档。我俩在里面详细标注了各个类的分工,以及各个函数的作用、输入参数与返回值。

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

    • 由于openCppCoverage在VS中下载缓慢,可以选择在marketplace中下载,目前还没有发现openCppCoverage插件可以用于检测单元测试覆盖率的功能,只能用它来检测整体代码覆盖率,得出覆盖率如下

    cover

    • 在网上查找,VS的单元测试覆盖率可能需要旗舰版才能完成,所以目前没有得出单元测试的结果,但是我们自己的单元测试编写的有层次有条理,尽可能做到了全面的覆盖。

    • 整体测试框架

      根据设计的几大类,采用bottom-up的方式进行测试程序的编写

      3单元测试
    • 对于每个类的每一个函数都进行了细密的测试

      比如下面展示的对于直线类的测试,细致到每一个函数

      TEST_CLASS(LineTest) {
      public:
      	TEST_METHOD(lineTestBasic) {
      		Line l1('L', 1, 1, 2, 2);
      		Line l2('R', 0, 2, 1, 0);
      		Line l3('S', 1, 0, 5, 0);
      
      		// test getType
      		Assert::IsTrue(l1.getType() == 'L');
      		Assert::IsTrue(l2.getType() == 'R');
      		Assert::IsTrue(l3.getType() == 'S');
      
      		// test get abc
      		Assert::IsTrue((l1.getA() == 1 && l1.getB() == -1) ||
      			(l1.getA() == -1 && l1.getB() == 1)
      			&& l1.getC() == 0);
      		Assert::IsTrue((l2.getA() == -2 && l2.getB() == -1 && l2.getC() == 2) ||
      			(l2.getA() == 2 && l2.getB() == 1 && l2.getC() == -2));
      
      		// test get p1 p2;
      		Point p1(1, 1);
      		Point p2(1, 0);
      		Point p3(5, 0);
      		Assert::IsTrue(l1.getP1() == p1);
      		Assert::IsTrue(l2.getP2() == p2);
      		Assert::IsTrue(l3.getP2() == p3);
      
      	}
      };
      
    • 对于求交点的重要复杂部分,我们的测试也做的更细致

      比如直线相交的测试,我们对于几种直线间的情况比如相交、平行、重叠,以及三种直线的情况(线段、射线、直线)都做了非常细致的测试

      3直线测试
      // test parallel
      		TEST_METHOD(LinePrl)
      		{
      			Calculator* calc = new Calculator();
            // 三种线段
      			char line = 'L';
      			char radio = 'R';
      			char segment = 'S';
      			Line lTD(line, 1, 3, 2, 3);
      			Line rTD(radio, 2, 5, 4, 5);
      			Line sTD(segment, 51, 6, 24, 6);
      			Calculator* cal = new Calculator();
      			Assert::IsTrue(cal->isParallerl(lTD, rTD));
      			Assert::IsTrue(cal->isParallerl(lTD, sTD));
      			Assert::IsTrue(cal->isParallerl(rTD, sTD));
      
      			Line l1(line, 3, 3, 5, 5);
      			Line r1(radio, 6, 5, -100, -101);
      			Line s1(segment, 0, 1, 100, 101);
      			Assert::IsTrue(cal->isParallerl(l1, r1));
      			Assert::IsTrue(cal->isParallerl(l1, s1));
      			Assert::IsTrue(cal->isParallerl(r1, s1));
      			Assert::IsFalse(cal->isParallerl(l1, sTD));
      			Assert::IsFalse(cal->isParallerl(r1, sTD));
      			Assert::IsFalse(cal->isParallerl(s1, rTD));
      		}
      

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

    异常处理设计

    • 几种异常
    1. 命令行输入异常(参数、文件名)
    2. 输入文件异常(输入曲线不符合格式,输入线段数目,“乱码”输入)
    3. 直线异常
    4. 曲线异常

    异常处理测试

    1.1. 命令行输入——参数异常

    intersect.exe -n 
    intersect.exe -i input.txt -o output.txt -h
    

    1.2. 命令行输入——文件名异常

    intersect.exe -i test.txt -o output.txt
    intersect.exe -i input.txt -o out.txt
    
    • 根据以上测试,得到异常处理测试结果

    3expCmd测试

    2.1. 输入文件内容——输入曲线不符合格式

    ## 1. 直线输入错误
    R 0 43 9 -3 98
    
    # 2. 输入几何对象参数含有前导0
    S 09 12 45 89
    
    # 3.  多个字母
    S S 3 2 1 
    
    # 4. 只有数字
    3 1 5 2 76
    
    # 5. 字母数字乱序
    5 L 1 4 6
    
    # 6. -后不接数字
    L - - - -
    
    # 7. 错误数字
    L 98-736 92 0 82
    

    2.2. 输入线段数目异常

    # 1. 输入线段 < 1
    0
    -94
    
    # 2. 输入线段与实际线段数不同
    1
    L 0 10 8 83
    R 91 46 2 0
    
    4
    L 56 28 82 4
    R 19 41 34 56
    C 56 168 5 
    

    2.3.曲线输入文件无法打开

    3.1. 直线不符合标准

    ## 1. 输入两点重合
    L 0 1 0 1 
    
    ## 2. 输入数字超范围
    R 100000 0 0 0
    L -100000 4897 278 1
    S -100005 3784 942 61
    

    3.2.有无穷多交点

    #1.  正确情况
    3
    S 1 1 3 3
    S 5 5 100 100
    R 0 0 -55 -55
    
    # 2. 异常
    2
    S 0 1 7 8
    R -4 -3 -3 -2
    
    2
    S 0 1 7 8
    L 9 10 100 101
    
    2
    R -4 -5 0 -1
    L -99 -100 -50 -51
    
    2 
    S 1 0 3 0
    S 2 0 4 0 
    
    2
    S 1 0 3 0
    S 2 0 3 0 
    
    2 
    S 1 0 3 0
    S 1 0 5 0 
    
    2
    S 1 0 3 0
    S 0 0 5 0
    

    4.1. 圆不符合标准

    ## 1. 输入圆半径小于1
    C 0 0 0
    
    C 84 72 -23
    
    ## 2. 输入数字超范围
    C -100000 4897 278
    
    • 对于以上的样例,分别写了测试样例,得到测试结果如下:

      epctest

    10.界面模快的详细设计过程

    这次的GUI我们是用Qt实现的。Qt的良好封装机制使得Qt的模块化程度非常高,可重用性较好,对于用户开发来说比较方便。 Qt提供了一种称为signals/slots的安全类型来替代 callback,使得各个元件之间的协同工作变得十分简单。

    (1)界面设计

    我们先通过集成在 Qt Creator 中的 Qt Designer 对窗体进行可视化设计。

    最终界面如下:

    pairProjectGUI

    为了方便用户操作、减少用户记忆负担、减少用户错误信息,我们的设计做了如下改良:

    • 关文件导入:我们实现的“..."按钮可直接浏览文件夹选择文件,无需手动输入路径。
    • 添加操作:由于几何对象的参数要求为在(-100000,100000)之间的不含前导零的整数,我们设置了SpinBox,其限制了正确的参数形式,避免手动输入带来的参数格式错误问题。对于几何体的类型,我们实现了下拉选框。
    • 删除操作:为了减少用户的记忆负担,我们在listWidget中实时呈现了当前几何图形。为了避免删除操作的错误信息和比较过程的繁琐,我们设置了复选框。用户选择列表中的几何图形,点击“删除几何图形”即可。这样既方便了用户,也减少了我们异常处理的负担。
    • 求解交点:点击“求解交点”按钮,则会计算出所有交点的左边,并在下方显示求解的交点数。
    • 绘制:在用户完成全部对当前几何图形的修改和求解交点后,点击“绘制几何图形和交点”按钮,我们将统一更新画布。这样避免了用户频繁的阶段性操作带来的无用计算。

    界面使用注意点:
    在点击求解交点后,方有交点的数据,才能绘制出交点。
    在点击绘制几何图形和交点后,才会更新当前几何图形的绘制。

    (2)主要代码说明

    Qt使用了信号和槽来代替回调函数,实现对象间的通信。当一个特定的事件发生时,信号会被发送出去。Qt的窗体部件(widget)拥有众多预先定义好的信号。槽,则是对一个特定的信号进行的反馈。我们这次的实现主要是创建窗体部件(widget)的子类并添加自定义槽,以便对感兴趣的信号进行处理。

    我们实现的类中,有两个重要的属性vector figuresvector points,分别存放当前几何对象当前交点

    a.文件导入

    //点击"..."按钮,浏览文件夹
    void IntersectGUI::on_findFileButton_clicked() 
    {
    	filePath =
    		QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Save path"), QDir::currentPath()));  //文件路径
    	if (!filePath.isEmpty())
    	{
    		if (ui.fileBox->findText(filePath) == -1)
    			ui.fileBox->addItem(filePath);//在comboBox中显示文件路径
    	}
    }
    //点击"输入文件"按钮,导入文件数据
    void IntersectGUI::on_infileButton_clicked()
    {
    	QFile* file = new QFile;   //申请一个文件指针
    	file->setFileName(filePath);   //设置文件路径
    	bool ok = file->open(QIODevice::ReadOnly);
    	if (ok)
    	{
    	……//读入文件并将文件中的数据处理后存入figures中	
    		}
    		file->close();
    	}
    }
    

    b.求解交点

    点击“求解交点”按钮,将当前几何体的数据转换成相应的接口处的数据,调用dll中的函数,计算交点并返回。具体接口设计,下一部分详细介绍。

    int IntersectGUI::on_calcPButton_clicked()
    {
    	points.clear();
    	std::string input;
    	size_t n = figures.size();
    	……//将figures中的几何体数据转换成相应的接口中的数据input
    	int cnt = 0;
    	//cnt = guiProcess(&points,figures);
    	try {
    		cnt = guiProcess(&points, input);
    	}
    	catch (std::exception e) {
    		QString dlgTitle = QString::fromLocal8Bit("计算出现错误");
    		QMessageBox::critical(this, dlgTitle, e.what());
    		return 0;
    
    	} {
    	}
    	ui.lineEdit->setText(QString::number(cnt));//反馈交点数
    	return cnt;
    }
    

    c.图形绘制

    这一部分,我们重写了paintEvent()方法。点击“绘制几何图形和交点”的按钮时,调用update()函数,重新绘制。

    void IntersectGUI::paintEvent(QPaintEvent*)
    {
    	init_canvas(); //初始化画布 (底色和坐标轴)
    	if (figures.size() != 0) {
    		for (vector<string>::iterator iter = figures.begin(); iter != figures.end(); ++iter) {
    			draw_figures_from_str(*iter);//绘制几何图形
    		}
    		draw_points();//绘制交点
    	}
    }
    
    void IntersectGUI::on_drawFigureButton_clicked()
    {
    	update();
    }
    
    //将不同的string数据绘制成不同的几何图形
    void IntersectGUI::draw_figures_from_str(string str)
    {
    	QStringList list = (QString::fromStdString(str)).split(" ");
    	QString type = list.at(0);
    	……
    	if (type == QString::fromLocal8Bit("L")) {
    		draw_line(x1, y1, x2, y2);
    	}
    	else if (type == QString::fromLocal8Bit("S")) {
    		draw_seg(x1, y1, x2, y2);
    	}
    	else if (type == QString::fromLocal8Bit("R")) {
    		draw_ray(x1, y1, x2, y2);
    	}
    	else {
    		draw_circle(x1, y1, r);
    	}
    }
    
    

    由于Qt中的drawLine()方法,只能绘制两点间的线段。所以在实现绘制直线和射线的时候,我们计算了当前线与画布边界的交点。代码简单,但是很长,在这里就不展示了。

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

    (1)接口数据格式介绍

    计算模块与界面模块的对接,用到了此接口:

    int guiProcess(std::vector<std::pair<double, double>> * points, std::string msg);

    msg存放的是当前几何图形的信息,数据格式与文件中读取的格式相同。如:

    4
    C 3 3 3
    S 2 4 3 2
    L -1 4 5 2
    R 2 5 -1 2
    

    points存放求解的交点。

    (2)GUI导入dll的方式如下:

    #pragma comment(lib,"calcInterface.lib")
    _declspec(dllexport)  extern "C"  int guiProcess(std::vector<std::pair<double, double>> * points, std::string msg);
    

    (3)具体代码实现

    GUI相关的代码只在求解交点处调用了dll的guiProcess()方法。

    int IntersectGUI::on_calcPButton_clicked()
    {
    	points.clear();
    	std::string input;
    	size_t n = figures.size();
        //转换数据
    	input += std::to_string(n) + "
    ";
    	for (size_t i = 0; i < n; i++) {
    		input += figures.at(i) + "
    ";
    	}
    	
    	int cnt = 0;
    	try {
    		cnt = guiProcess(&points, input);
    	}
    	catch (std::exception e) {
    		...
    	} {
    	}
    	ui.lineEdit->setText(QString::number(cnt));//界面反馈交点总数
    	return cnt;
    }
    

    IntersectGUI类中的vector<std::pair<double, double>> points属性存放求解的交点。在调用guiProcess前,清空当前points中的元素,传入points的引用。将figures中的数据转换为接口对应类型的数据传入。guiProcess()会将求解的交点写入points中,并返回交点数。

    guiProcess()代码如下:

    int guiProcess(std::vector<std::pair<double, double>>* points, 
    	std::string msg) {
    	try {
    		vector<Line> lVec;
    		vector<Circle> cVec;
            //将msg中的几何信息解析并存入lVec和cVec中
    		istringstream input(msg);
    		fileExcHandler(input, lVec, cVec);
            //计算交点
    		set<Point> pointSet = getAllIntersect(lVec, cVec);
            //将交点信息写入points中
    		for (auto iter = pointSet.begin(); iter != pointSet.end(); iter++) {
    			Point p = (Point)* iter;
    			points->push_back(make_pair(p.getX(), p.getY()));
    		}
            //返回交点总数
    		return (int)pointSet.size();
    	} catch (fileException& fileError) {
    		cout << fileError.what() << endl;
    	}
    	catch (lineException& lineError) {
    		cout << lineError.what() << endl;
    	}
    	catch (CircleException& circleError) {
    		cout << circleError.what() << endl;
    	}
    	return -1;
    }
    

    (4)对接相关功能实现

    未点击“求解交点”按钮时,绘制的几何图形。

    1584982017704

    点击“求解交点”按钮后,再绘制

    GUI3

    绘制交点并返回交点数。

    12.结对过程

    时间表

    时间 事项
    3.12晚 讨论结对编程总体规划
    3.12-3.14 独立进行需求分析、学习和设计的工作,辅以资源交流
    3.14下午 讨论代码设计,确定最终设计和实际结对编程的各种方法和规范
    3.14晚-3.16上午 进行合作编程,完成step1的功能及其测试
    3.18-3.21 改进接口设计,并完成GUI部分和异常处理部分
    3.23-3.24 完成博客部分

    工具使用

    13.结对编程总结

    • 结对编程本身

      • 优点
        • 在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。
        • 对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感
        • 在心理上, 当有另一个人在你身边和你紧密配合, 做同样一件事情的时候, 你不好意思开小差, 也不好意思糊弄
        • 在企业管理层次上,结对能更有效地交流,相互学习和传递经验,能更好地处理人员流动。因为一个人的知识已经被其他人共享
      • 缺点
        • 两人合作需要磨合,并不一定合得来。
        • 开发者之间可能就某一问题发生分歧,产生矛盾,造成不必要的内耗
    • 本人在结对编程中的表现

      • 优点
        • 能积极完成工作
        • 善于寻求帮助。(在这里要特别感谢zwx大佬和助教,被我问了很多问题,帮我解决了不少困惑~谢谢!)
        • 学习能力较强。这次作业让我学会了用Qt写GUI,虽然熬了不少夜,但能学习新知识,还是蛮开心的!
      • 缺点
        • 相比于我的队友,我的计划性就没那么强了。ddl玩家,这次就被我的队友拿着计划表一次次push。
        • 比较执着,不太会让步。这应该是我性格中的缺点了,认定了就很偏执,得改。
        • 深层次的问题不了解,解决问题的能力有待提高。这次开发过程中碰到的跟编译器有关的问题不是很懂,debug花了很长时间。
    • 队友在结对编程中的表现

      • 优点

        • 她比较积极主动,也经常担任项目中的领导工作。在作业发布后不久,我们就联系交流作业了。
        • 计划性强,在开发初期对各个部分有清晰的时间安排,做事有条理。
        • 善于沟通,结识的人广。她在项目初期就联系了合作小组。我们早早沟通商量,减少了很多对接工作的负担。
      • 缺点

        由于疫情原因,我们并不能在编程时实时保持交流,加上我电脑有一天晚上坏了。所以对于接口的设计部分她与合作小组确定了方案,却未能与我及时沟通。这也不是缺点,只是结对过程中的一点小矛盾。里面也有我的错,我太执着己见了。不过好在我们愉快得解决了这个问题,最终达成共识。

    14. PSP表回填(见2)

    界面模块,测试模块和核心模块的松耦合【附加题】

    • 和我们(A组)进行松耦合对接的是1602108817373439结对编程(B)小组
    • dll导出,即新建dll导出项目,在pch.h 文件中导入头文件,并在每一个*.cpp文件中include "pch.h文件,之后生成dll即可
    • 之后与GUI和cmd程序分别对接,其中有一个需要注意的问题,就是dll导出的编译器需要和导入文件的编译器相同,否则就会出现无法导入的情况,我们两个小组都采用的VS IDE上的release x64版本的编译器,下面展示松耦合实际测试

    cmd松耦合

    • B组dll导入A组cmd程序

    3cmdA->B

    • A组dll导入B组cmd程序

      BceAcmd

    • B组dll导入A组GUI程序

      AceBGUI

    • A组dll导入B组GUI程序

      BceAGUI

    由于我们两个小组在项目初期就确定了合作,所以接口设计是在双方商量好的情况下早早决定了的。对接过程中,碰到的唯一问题是编译版本问题。B组的dll是Release X64编译的,而我们是Debug X64编译的,导致开始对接时总是导入不成功。后来我们统一了编译版本(Release X64),问题也就解决了。
    由于我们之前没有将dll同名,现已经改成统一名字。只需互换dll无需再编译即可运行,更改后的GUI版本和dll已经发布到github上了。

  • 相关阅读:
    ZJNU 1138
    ZJNU 1133
    架构设计:系统存储(21)——图片服务器:详细设计(1)
    架构设计:系统存储(20)——图片服务器:需求和技术选型(2)
    架构设计:系统存储(19)——图片服务器:需求和技术选型(1)
    架构设计:系统存储(18)——Redis集群方案:高性能
    大端模式和小端模式
    阶段性纠错邀请
    架构设计:系统存储(17)——Redis集群方案:高可用
    Android深入浅出之Binder机制
  • 原文地址:https://www.cnblogs.com/lzh-blod/p/12560392.html
Copyright © 2011-2022 走看看