201871030121-马艳 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

项目 内容
课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/2018CST
这个作业要求链接 https://www.cnblogs.com/nwnu-daizh/p/14604444.html
我的课程学习目标 体验软件项目开发中的两人合作,练习结对编程(Pair programming),掌握Github协作开发程序的操作方法。
这个作业在哪些方面帮助我实现学习目标 通过两人协作更好的了解到自己的不足以及学习对方的知识能力,互相交流,发现问题,更好的练习编程。
结对方学号-姓名 201871030128-魏娜娜
结对方本次博客作业链接 https://www.cnblogs.com/weinana/p/14655832.html
本项目Github的仓库链接地址 https://github.com/ma77275/test3

任务一:

  • 阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念。
    • 我们所讲的“代码规范“一般是指两个方面:
      • (1)代码风格规范。主要是文字上的规定,看似表面文章,实际上非常重要。
      • (2)代码设计规范。牵涉到程序设计、模块之间的关系、设计模式等方方面面,这里有不少与具体程序设计语言息息相关的内容(如C/C++/Java/C#),但是也有通用的原则,这里主要讨论通用的原则。

(一)、代码风格规范

  • 代码风格的原则是:简明,易读,无二义性

    • (1)缩进:4个空格,在VS2005和其他的一些编辑工具中都可以定义Tab键扩展成为几个空格键。不用 Tab键的理由是Tab键在不同的情况下会显示不同的长度。4个空格的距离从可读性来说正好。

    • (2)行宽:行宽必须限制,可为100字符。

    • (3)括号:在复杂的条件表达式中,用括号清楚地表示逻辑优先级。

    • (4)断行与空白的{ }行:

      ​ 一般我们选择,每个“{”和“}”都独占一行。如下:

           if ( condition)
           {
              DoSomething();
           }
              else
           {
             DoSomethingElse();
           }
      
    • (5)分行:不要把多行语句放在一行上。

      ​ a = 1; b = 2; // bogus

      ​ if (fFoo) Bar(); // bogus

      ​ 更严格地说,不要把不同的变量定义在一行上。

      ​ Foo foo1, foo2; // bogus

    • (6)命名: 目前最通用的,经过了实践检验的方法叫“匈牙利命名法” ,但在一些一些强类型的语言(C#)中不适用。

    • (7)下划线问题: 下划线用来分隔变量名字中的作用域标注和变量的语义。

    • (8)大小写问题:由多个单词组成的变量名,如果全部都是小写,很不易读,一个简单的解决方案就是用大小写区分它们。

      ​ Pascal——所有单词的第一个字母都大写;

      ​ Camel——第一个单词全部小写,随后单词随Pascal格式,这种方式也叫lowerCamel。

      ​ 一个通用的做法是:所有的类型/类/函数名都用Pascal形式,所有的变量都用Camel形式。

      ​ 类/类型/变量:名词或组合名词,如Member、ProductInfo等。

      ​ 函数则用动词或动宾组合词来表示,如get/set; RenderPage()。

    • (9)注释:复杂的注释应该放在函数头,很多函数头的注释都是解释参数的类型等的,如果程序正文已经能够说明参数的类型in/out等,就不要重复!

      ​ 注释也要随着程序的修改而不断更新,一个误导的(Misleading)注释往往比没有注释更糟糕。

      ​ 另外,注释(包括所有源代码)应只用ASCII字符,不要用中文或其他特殊字符,它们会极大地影响程序的可移植性。

      ​ 在现代编程环境中,程序编辑器可以设置各种好看的字体,我们可以使用不同的显示风格来表示程序的不同部分。

(二)、代码设计规范:

  • 代码设计规范不光是程序书写的格式问题,而且牵涉到程序设计、模块之间的关系、设计模式等方方面面,这里有不少与具体程序设计语言息息相关的内容(如C、C++、Java、C#),但是也有通用的原则。

    • (1)函数:现代程序设计语言中的绝大部分功能,都在程序的函数(Function, Method)中实现,关于函数最重要的原则是:只做一件事,但是要做好。

    • (2)goto:函数最好有单一的出口,为了达到这一目的,可以使用goto。只要有助于程序逻辑的清晰体现,什么方法都可以使用,包括goto。

    • (3)错误处理:

      ​ 1.参数处理

      ​ 在DeBug版本中,所有的参数都要验证其正确性。在正式版本中,从外部(用户或别的模块)传递过来的参数要验证其正确性。

      ​ 2.断言

      ​ 如何验证正确性?那就要用Assert(断言)。断言和错误处理是什么关系?

      ​ 当你觉得某事肯定如何,你可以用断言。

      ​ Assert (p != NULL);

      ​ 然后可以直接使用变量p;

      ​ 如果你认为某事可能会发生,这时就要用错误处理。

    • (4)如何处理C++中的类

      ​ 注意,除了关于异常(Exception)的部分,大部分其他原则对C#也适用。

      ​ 1.类

      ​ (1)使用类来封装面向对象的概念和多态(Polymorphism)。

      ​ (2)避免传递类型实体的值,应该用指针传递。换句话说,对于简单的数据类型,没有必要用类来实现。

      ​ (3)对于有显式的构造和析构函数,不要建立全局的实体,因为你不知道它们在何时创建和消除。

      ​ (4)只有在必要的时候,才使用“类”。

      ​ 2.Class vs. Struct 如果只是数据的封装,用Struct即可。

      ​ 3.公共/保护/私有成员Public、Private和Protected

      ​ 按照这样的次序来说明类中的成员:public、protected、private

      ​ 4.数据成员

      ​ (1)数据类型的成员用m_name说明。

      ​ (2)不要使用公共的数据成员,要用inline访问函数,这样可同时兼顾封装和效率。

      ​ 5.虚函数Virtual Functions

      ​ (1)使用虚函数来实现多态(Polymorphism)。

      ​ (2)只有在非常必要的时候,才使用虚函数。

      ​ (3)如果一个类型要实现多态,在基类(Base Class)中的析构函数应该是虚函数。

      ​ 6.构造函数Constructors

      ​ (1)不要在构造函数中做复杂的操作,简单初始化所有数据成员即可。

      ​ (2)构造函数不应该返回错误(事实上也无法返回)。把可能出错的操作放到HrInit()或FInit()中。

      ​ 7.析构函数

      ​ (1)把所有的清理工作都放在析构函数中。如果有些资源在析构函数之前就释放了,记住要重置这些成员为0或NULL。

      ​ (2)析构函数也不应该出错。

      ​ 8.New和Delete

      ​ (1)如果可能,实现自己的New/Delete,这样可以方便地加上自己的跟踪和管理机制。自己的New/Delete可以包装系统提供的New/Delete。

      ​ (2)检查New的返回值。New不一定都成功。

      ​ (3)释放指针时不用检查NULL。

      ​ 9.运算符(Operators)

      ​ (1)在理想状态下,我们定义的类不需要自定义操作符。只有当操作符的确需要时。

      ​ (2)运算符不要做标准语义之外的任何动作。例如,“==”的判断不能改变被比较实体的状态。

      ​ (3)运算符的实现必须非常有效率,如果有复杂的操作,应定义一个单独的函数。

      ​ (4)当你拿不定主意的时候,用成员函数,不要用运算符。

      ​ 10.异常(Exceptions)

      ​ (1)异常是在“异乎寻常”的情况下出现的,它的设置和处理都要花费“异乎寻常”的开销,所以不要用异常作为逻辑控制来处理程序的主要流程。

      ​ (2)了解异常及处理异常的花销,在C++语言中,这是不可忽视的开销。

      ​ (3)当使用异常时,要注意在什么地方清理数据。

      ​ (4)异常不能跨过DLL或进程的边界来传递信息,所以异常不是万能的。

      ​ 11.类型继承(Class Inheritance)

      ​ (1)当有必要的时候,才使用类型继承。

      ​ (2)用Const标注只读的参数(参数指向的数据是只读的,而不是参数本身)。

      ​ (3)用Const标注不改变数据的函数。

(三)、代码复审

  • 代码复审的正确定义:看代码是否在“代码规范”的框架内正确地解决了问题。

    名称 形式 目的
    自我复审 自己 vs. 自己 用同伴复审的标准来要求自己。不一定最有效,因为开发者对自己总是过于自信。如果能持之以恒,则对个人有很大好处
    同伴复审 复审者 vs. 开发者 简便易行
    团队复审 团队 vs. 开发者 有比较严格的规定和流程,用于关键的代码,以及复审后不再更新的代码。覆盖率高——有很多双眼睛盯着程序。但是有可能效率不高(全体人员都要到会)
  • 复审的目的在于:

​ (1)找出代码的错误。如:

​ a. 编码错误,比如一些能碰巧骗过编译器的错误。

​ b. 不符合项目组的代码规范的地方。

​ (2)发现逻辑错误,程序可以编译通过,但是代码的逻辑是错的。

​ (3)发现算法错误,比如使用的算法不够优化。

​ (4)发现潜在的错误和回归性错误——当前的修改导致以前修复的缺陷又重新出现。

​ (5)发现可能改进的地方。

​ (6)教育(互相教育)开发人员,传授经验,让更多的成员熟悉项目各部分的代码,同时熟悉和应用领域相关的实际知识。

(四)、结对编程

​ 每人在各自独立设计、实现软件的过程中不免要犯这样那样的错误。在结对编程中,因为有随时的复审和交流,程序各方面的质量取决于一对程序员中各方面水平较高的那一位。这样,程序中的错误就会少得多,程序的初始质量会高很多,这样会省下很多以后修改、测试的时间。具体地说,结对编程有如下的好处:

​ (1)在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。

(2)对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感。

(3)在心理上, 当有另一个人在你身边和你紧密配合, 做同样一件事情的时候, 你不好意思开小差, 也不好意思糊弄。

(4)在企业管理层次上,结对能更有效地交流,相互学习和传递经验,能更好地处理人员流动。因为一个人的知识已经被其他人共享。

任务二:

  • 两两*结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价,具体要求如下:

    (1)对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。

    ​ 已完成。

    (2)克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并

    记录。

    结对对象:魏娜娜:

    GitHub链接地址:https://github.com/we446/222/commit/4768834cc87fae867e55eb5fc8dced8cedd7c374

    复审部分 提出问题 执行情况
    概要部分 1)代码符合需求和规格说明么? 2)代码设计是否考虑周全? 3)代码可读性如何? 4)代码容易维护么? 5)代码的每一行都执行并检查过了吗? 1)代码部分符合基本的要救和规格说明,注释部分也很齐全; 2)代码设计方面并没有达到理想的效果,功能并没有完全实现 3)代码的可读性比较困难,因为对于部分代码并没有进行注释4)代码容易维护5)代码的每一行都执行并检查过了
    设计规范部分 1)设计是否遵从已知的设计模式或项目中常用的模式? 2)有没有硬编码或字符串/数字等存在? 3)代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到 Win64 ) ? 4)开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现?在本项目中是否存在类似的功能可以调用而不用全部重新实现? 5)有没有无用的代码可以清除? 1)设计遵从项目中的常用模式 2)有字符串和数字存在 3)开发者新写的代码无法用已有的Library/SDK/Framework中的功能实现 4)基本没有无用代码
    代码规范部分 修改的部分符合代码标准和风格吗? 修改的部分符合代码标准和风格
    具体代码部分 1)有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常? 2)参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以0开始计数还是以1开始计数? 3)边界条件是如何处理的?switch语句的default分支是如何处理的?循环有没有可能出现死循环? 4)有没有使用断言(Assert)来保证我们认为不变的条件真的得到满足? 5)对资源的利用,是在哪里申请,在哪里释放的?有无可能存在资源泄漏(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有优化的空间? 6)数据结构中有没有用不到的元素? 对错误进行了处理,参数传递没有出现问题,没有使用断言(Assert)来保证我们认为不变的条件真的得到满足。
    效能 1)代码的效能( Performance )如何?最坏的情况是怎样的? 2)代码中,特别是循环中是否有明显可优化的部分(C++中反复创建类,C# 中 string的操作是否能用StringBuilder来优化)? 3)对于系统和网络的调用是否会超时?如何处理? 代码的效能不是很好,对于代码的处理并没有完全完成任务,以及算法的实现。
    可读性 代码可读性如何?有没有足够的注释? 代码可读性较好,有足够的注释
    可测试性 代码是否需要更新或创建新的单元测试? 不需要

    (3)依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。

任务三:

  • 采用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台,使之具有以下功能:

    (1)平台基础功能:实验二 任务3;

    (2)D{0-1}KP 实例数据集需存储在数据库;

    (3)平台可动态嵌入任何一个有效的D{0-1}KP 实例求解算法,并保存算法实验日志数据;

    (4)人机交互界面要求为GUI界面(WEB页面、APP页面都可);

    (5)查阅资料,设计遗传算法求解D{0-1}KP,并利用此算法测试要求(3);

    (6)附加功能:除(1)-(5)外的任意有效平台功能实现。

    1、需求分析陈述

    ​ 背包问题是一个经典的组合优化问题,有着广泛而重要的应用背景。{0-1}背包问题是最基本的KP问题形式,它的一般描述为:从若干具有价值系数与重量系数的物品(或项)中,选择若干个装入一个具有载重限制的背包,如何选择才能使装入物品的重量系数之和在不超过背包载重前提下价值系数之和达到最大?

    ​ 在处理到第i个物品时,可以假设一共只有i个物品,如果前面i-1个物品的总的最大价值已经定下来了,那么第i个物品选不选将决定这1~i个物品能带来的总的最大价值。刚刚是自顶向下,接下来反过来自底向上,第1个物品选不选可以轻松地用初始化解决,接下来处理第i个物品时,假设只有2个物品就好,那他处理完后前2个物品能带来的最大总价值就确定了,这样一直推下去,就可以推出前n个物品处理完后能带来的最大总价值。

    ​ 对于每个背包,都只有0和1的情况,也就是拿或者不拿两种情况

    ​ 如果拿:那么空间就会减一点,比如说现在在考虑第i个物品拿不拿,如果说当前剩余空间为j,那么拿了之后空间就变为j-c[i],但是总价值却会增加一点,也就是增加w[i]

    ​ 如果不拿:那么空间不会变,还是j,但是总价值也不会变化。

    2、软件设计说明

    ​ 分析遗传算法,基于实验二来扩展其功能,连接数据库,设计人机交互界面,在编程中使用结对编程的方式,然后代码复审

    3、软件实现及核心功能代码展示:

    ​ 此次实验设计运用到了遗传算法,遗传算法是用于解决最优化问题的一种搜索算法。从名字来看,遗传算法借用了生物学里达尔文的进化理论:”适者生存,不适者淘汰“,将该理论以算法的形式表现出来就是遗传算法的过程。

    遗传算法核心代码:

    while iteration < self.iteration:  # 设置迭代次数300
      
                  parents = self.selection(init_population)  # 选择后的父代
                  children = self.crossover(parents)
                  mutation_children = self.mutation(children)
    
                  init_population = mutation_children
     
                  f_set = []  # 求出每一步迭代的最大值
                  for init in range(init_population.shape[1]):
                      f_set_tem = self.fitness_function(init_population[:, init])
                      f_set.append(f_set_tem)
      
                  f_set = max(f_set)
      
                  f_set_plot.append(f_set)
      
                  iter_plot.append(iteration)
                  iteration = iteration+1
                  print("第%s进化得如何******************************************" % iteration)
                  f_average = self.fitness_average(init_population)
                  f_plot.append(f_average)
                  print(f_set)
                  # f_accumulation = f_accumulation + f
                  # f_print = f_accumulation/(iteration + 1)
                  # print(f_print)
              self.plot_figure(iter_plot, f_plot, f_set_plot)
    

    GUI界面核心代码:

    def usr_log_in():
        #输入框获取用户名密码
        usr_name=var_usr_name.get()
        usr_pwd=var_usr_pwd.get()
        #从本地字典获取用户信息,如果没有则新建本地数据库
        try:
            with open('usr_info.pickle','rb') as usr_file:
                usrs_info=pickle.load(usr_file)
        except FileNotFoundError:
            with open('usr_info.pickle','wb') as usr_file:
                usrs_info={'admin':'admin'}
                pickle.dump(usrs_info,usr_file)
        #判断用户名和密码是否匹配
        if usr_name in usrs_info:
            if usr_pwd == usrs_info[usr_name]:
                tk.messagebox.showinfo(title='welcome',
                                       message='欢迎您:'+usr_name)
            else:
                tk.messagebox.showerror(message='密码错误')
        #用户名密码不能为空
        elif usr_name=='' or usr_pwd=='' :
            tk.messagebox.showerror(message='用户名或密码为空')
        #不在数据库中弹出是否注册的框
        else:
            is_signup=tk.messagebox.askyesno('欢迎','您还没有注册,是否现在注册')
            if is_signup:
                usr_sign_up()
    

    4、程序运行截图

    201871030121-马艳 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    5、描述结对的过程,提供两人在讨论、细化和编程时的结对照片(非摆拍)

    201871030121-马艳 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    201871030121-马艳 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    201871030121-马艳 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    6、此次结对作业的PSP展示

    任务内容 计划共完成需要的时间 实际完成的时间
    计划 460 510
    估计这个任务需要多长,并规划大致工作步骤 20 30
    开发 40 30
    需求分析 20 10
    生成设计文档 30 40
    设计审核 30 20
    代码规范 20 20
    具体设计 50 60
    具体编码 120 120
    代码复审 20 30
    测试 30 40
    报告 20 30
    测试报告 30 40
    计算工作量 10 20
    事后总结,并提出过程改进计划 20 20

    7、小结感受

    ​ 此次博客任务是建立在实验二的基础之上,是对上次任务的完善,通过两人协作互相交流,修改自己的代码,学习对方的编程代码,共同规划任务时间,建立psp表格,但是此次的任务并没有完成的很好,对于数据库的连接并没有实现,明白自己还是有很多的不足,对于知识的运用也没有达到很好的效果。

任务四:

  • 完成结对项目报告博文作业
    201871030121-马艳 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
上一篇:c#-无法覆盖Mono-2.10.8中的加密提供程序


下一篇:SVD | 简介推荐场景中的协同过滤算法,以及SVD的使用