201971010138-汤可意 实验三 结对项目—《{0-1}KP 实例数据集算法实验平台》项目报告
【keyi21】软件工程准备报告[实验三]
201971010139-汤可意 实验三 结对项目—《{0-1}KP 实例数据集算法实验平台》项目报告
项目 | 内容 |
---|---|
课程班级博客链接 | https://edu.cnblogs.com/campus/xbsf/2019nwnucs |
作业要求链接 | https://edu.cnblogs.com/campus/xbsf/2019nwnucs/homework/12560 |
我的课程学习目标 | 1.体验软件项目开发中的两人合作,练习结对编程; 2. 掌握Github协作开发程序的操作方法; 3.阅读《现代软件工程—构建之法》学习代码规范等知识。 |
这个作业在哪些方面帮助我实现学习目标 | 1.熟悉了软件工程结对编程; 2.掌握Github克隆结对方项目; 3.学习了代码风格规范、代码设计规范、代码复审等知识; |
结对方学号-姓名 | 201971010142-王玉慧 |
结对方本次博客作业链接 | 201971010142-王玉慧 |
本项目Github的仓库链接地址 | 201971010138-keyi21 |
·任务一 阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;
1.代码风格规范:
代码风格规范包括命名规范,代码展示风格的规范(缩进、空格、换行),控制语句的规范以及代码注释的规范,好的代码风格规范可以让其他人更好的理解。它的原则是:简明,易读,无二义性。具体设计规则如下:
- 四个空格的缩进
- 每个{}独占一行
- 不要把多个变量定义在一行上
- 一个类型的成员变量用同一类型命名
- 所有的类型/类/函数名
- 注释是为了解释程序做什么(What),为什么这么做(Why),以及要特别注意的地方,只用ASCII字符,不要用中文
2.代码设计规范:
- 函数:只做一件事,并且要做好
- 单一出口
- 不要在构造函数中做复杂的操作,简单初始化所有的数据成员即可
3.代码复审:
看代码是否在代码规范的框架内正确地解决了问题、长远的问题;
- 修改之后,有没有别的功能会受影响;
- 项目中还有别的地方需要类似的修改吗;
- 有没有留下足够的说明,让将来维护代码时不会出现问题;
- 对于修改,是否需要告知成员;
- 导致问题的根本原因是什么?以后如何能自动避免这样的情况再次出现;
4.结对编程
结对编程是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员,审查代码的人称作观察员。两个程序员经常互换角色。
在结对编程中,观察员同时考虑工作的战略性方向,提出改进的意见,或将来可能出现的问题以便处理。这样使得驾驶者可以集中全部注意力在完成当前任务的“战术”方面。观察员当作安全网和指南。结对编程对开发程序有很多好处。比如增加纪律性,写出更好的代码等。
结对编程是极端编程的组成部分。
·任务2:两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价
1.项目要求:
- 对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。
- 克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
- 依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
2.项目完成:
- 结对方博客链接:包凤梅的博客
- 结对方Github项目仓库链接:王玉慧Github项目仓库链接
- 博客评论:
评论地址:201971010142-王玉慧
评论内容:
- 代码核查表
项目 | 内容 |
---|---|
概要部分 | a.代码书写符合需求和规格说明; b.代码设计没有考虑周全,有很多代码使用的很不合适; c.代码可读性还性吧,不过有的还存在很多问题; d.代码比较容易维护; e.对结对方代码进行了逐行检查与运行。 |
设计规范部分 | a.代码遵循了已知的设计模式和在项目中的常用模式, 学习了很多知识。 b.我代码设计中有字符串和数字的存在。 c.程序代码没有依赖于某一平台,从Win32移植到Win64上没有出现很大的问题。 d.在本程序中类似的功能差不多都可以调用而不用全部重新来实现。 e.有无用的代码可以删除,在我的抽签程序中,我对于按组抽签中的添加人员姓名进行了编码,实际上是不需要的,因为一个学号就做够啦,而且还有窗体控件的功能实现。 |
代码规范部分 | a.修改的部分有很多地方是符合代码标准和风格的,但是有也有代码是没有符合标准和风格的。 |
具体代码部分 | a.在抽签程序中对错误进行了处理,在实现号码滚动的代码上出现了错误,只能实现代码中的数字,而不能随机的进行输入数字。对于调用的外部函数,检查了返回值。 b.参数传递无错误,字符串的长度是字节的长度,是双字节,是以1开始计数 c.Switch语句的用的很好,没有出现死循环 d.没有使用断言(Assert)来保证我们认为不变的条件真的满足 f.对资源的利用,是在C#书上借鉴的,内存、文件、各种GUI资源、数据库访问的连接没有可能导致资源泄露,有可能优化 e.数据结构中有很的元素是没有用到的。 |
效能 | a.代码中,特别是循环中没有明显可优化的部分。 b.对于系统和网络调用会超时,可以等待一会。 |
可读性 | 代码可读性很易懂,没有足够的注释,代码量很少。 |
可测试性 | 代码需要更新和创建新的单元测试。 可以针对部分功能的实现对代码进行进一步改进或创建新的单元测试。 |
3.依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
GitHub部分操作介绍:
- Fork:从别人发布的项目上复制一个过来,相当于一个分支;项目复制到自己的个github中,于是本地就有了一个仓库,假设名字为A;
- Clone:从自己的github上把fork过来的复制到本地,这样本地就有了一个项目A1;
- Push:当你在A1中进行修改进行开发后,最后同步到你的github上的仓库中;
- Pull request:你把自己github中的已经修改的内容申请同步到最初那个开发者的项目中;
·任务3:两两采用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台
1.功能要求:
- 平台基础功能:实验二 任务3;
- {0-1}KP 实例数据集需存储在数据库;
- 平台可动态嵌入任何一个有效的{0-1}KP 实例求解算法,并保存算法实验日志数据;
- 人机交互界面要求为GUI界面(WEB页面、APP页面都可);
- 查阅资料,设计遗传算法求解{0-1}KP,并利用此算法测试要求(3);
- 附加功能:除(1)-(5)外的任意有效平台功能实现。
2.功能分析:
- 可读取实验数据,有效呈现所有数据;
- 用读取的数据绘制出以重量为横轴、价值为纵轴的数据散点图;
- 将数据按项集第三项的价值:重量比进行非递增排序;
- 用户能够自主选择动态规划算法、回溯算法求解数据的最优解和求解时间;
- 数据的最优解、求解时间和解向量可保存为txt文件
3.软件设计
本次结对编程项目采用C/S结构进行,项目分两部分,一部分是客户端的编写,客户端主要处理本地读取的数据和传输数据到服务器和数据库,还有从服务器读取数据库中存储的结果,一部分是服务器端的编写,主要是连接数据库,接收信息,返回信息。客户端和服务器端双方通过tcp链接,并且在此基础上自定义协议进行通信和操作。同时本次项目采用了.net core平台作为开发平台,它具有跨平台、易开发等多种特点,在本次开发中尽量减少在重复工作上的工作量。
具体实现项目:
- D{0-1}KP 实例数据集需存储在数据库;
- 平台可动态嵌入任何一个有效的D{0-1}KP 实例求解算法,并保存算法实验日志数据;
- 人机交互界面要求为GUI界面;
- 查阅资料,设计遗传算法求解D{0-1}KP,并利用此算法测试要求(3);
4.软件实现及核心功能代码展示
-
DatabaseController(请求数据库操作)
package com.chm.bag_system.controller; public class DatabaseController { @Resource DataService dataService; @Resource CapacityService capacityService; @GetMapping("/save/data/database") public String insert(){ int count = capacityService.count(null); if (count>0){ return "redirect:/database"; } // 存储所有文件名的列表 ArrayList<String> files=new ArrayList<>(); files.add("idkp1-10.txt"); files.add("sdkp1-10.txt"); files.add("udkp1-10.txt"); files.add("wdkp1-10.txt"); for (String file : files) { ReadFile rf = new ReadFile(); try { rf.clearData(file); } catch (IOException e) { e.printStackTrace(); } rf.replaceCharacter(); rf.separateVolume(); Result result = rf.resultData(); insertDataBase(result); } return "database"; } /** * 将数据插入到数据库 * @param result */ private void insertDataBase(Result result) { for (String profit : result.getProfits()) { Data fileData = new Data(); fileData.setContent(profit); fileData.setType("价值"); fileData.setTeam(result.getProfits().indexOf(profit)+1); fileData.setFile(result.getFileName()); dataService.save(fileData); } for (String weight : result.getWeights()) { Data fileData = new Data(); fileData.setContent(weight); fileData.setType("重量"); fileData.setTeam(result.getWeights().indexOf(weight)+1); fileData.setFile(result.getFileName()); dataService.save(fileData); } for (String volume : result.getVolumes()) { Capacity volume1 = new Capacity(); volume1.setSize(Integer.parseInt(volume)); volume1.setTeam(result.getVolumes().indexOf(volume)+1); volume1.setFile(result.getFileName()); capacityService.save(volume1); } } }
-
ScatterController(散点图绘制)
package com.chm.bag_system.controller; @Controller public class ScatterController { @Resource DataService dataService; // 存放当前组价值的整型列表 private static ArrayList<Integer> profitList=new ArrayList<>(); // 存放当前组重量的整型列表 private static ArrayList<Integer> weightList=new ArrayList<>(); // 存放当前散点图数据的列表 private static ArrayList<ArrayList<Integer>> scatterData=new ArrayList<ArrayList<Integer>>(); @PostMapping("/scatter/query") public String queryData(Scatter scatter, Model model){ if(scatter.getFileName().equals("")||scatter.getGroup().equals("")){ model.addAttribute("data",null); return "scatter"; } profitList.clear(); weightList.clear(); scatterData.clear(); QueryWrapper<Data> wrapper = new QueryWrapper<Data>(); wrapper.eq("file",scatter.getFileName()); wrapper.eq("team",scatter.getGroup()); List<Data> list = dataService.list(wrapper); HandleData handleData = new HandleData(); for (Data data : list) { if (data.getType().equals("价值")) { handleData.splitDataIntoInteger(profitList,data.getContent()); } if (data.getType().equals("重量")) { handleData.splitDataIntoInteger(weightList,data.getContent()); } } for (int i = 0; i < weightList.size(); i++) { ArrayList<Integer> integers = new ArrayList<>(); integers.add(weightList.get(i)); integers.add(profitList.get(i)); scatterData.add(integers); } model.addAttribute("data",scatterData); return "scatter"; } }
-
往数据库里面存储数据
- 对选定的某个文件夹中的某一组绘制散点图
- 选择将要排序的具体组数
- 对某一组组数据项集按第三项性价比进行排序
- 用回溯算法求最优解
- 用动态规划算法求最优解
- 数据库中按组数存储的数据
- 数据库中每一项数据的价值与重量
- 有关遗传算法的使用
遗传算法(Genetic>遗传算法(Genetic Algorithm,GA)是进化计算的一部分,是模拟达尔文的遗传选择和自然淘汰的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法简单、通用,鲁棒性强,适于并行处理。
遗传算法基本流程:- 通过随机方式产生若干由确定长度(长度与待求解问题的精度有关)编码的初始群体;
- 通过适应度函数对每个个体进行评价,选择适应度值高的个体参与遗传操作,适应度低的个体被淘汰;
- 经遗传操作(复制、交叉、变异)的个体集合形成新一代种群,直到满足停止准则(进化代数GEN>=?);
- 将后代中变现最好的个体作为遗传算法的执行结果。
其中,GEN是当前代数;M是种群规模,i代表种群数量。
5.描述结对的过程,提供两人在讨论、细化和编程时的结对照片(非摆拍)。
6.本次结对实验PSP
PSP3.1 | 任务内容 | 计划共完成需要的时间(min) | 实际完成需要的时间(min) |
---|---|---|---|
Planning | 计划 | 6 | 8 |
- Estimate | - 估计这个任务需要多少时间,并规划大致工作步骤 | 6 | 8 |
Development | 开发 | 510 | 600 |
- Analysis | - 需求分析(包括学习新技术) | 10 | 6 |
- Design Spec | - 生产设计文档 | 10 | 8 |
- Design Review | - 设计复审(和同事审核设计文档) | 5 | 6 |
- Coding Standard | - 代码规范(为目前的开发指定合适的规范) | 10 | 20 |
- Design | - 具体设计 | 25 | 30 |
- Coding | - 具体编码 | 500 | 600 |
- Code Review | - 代码复审 | 30 | 30 |
- Test | - 测试(自我测试,修改代码,提交修改) | 120 | 200 |
Reporting | 报告 | 60 | 62 |
- Test Report | - 测试报告 | 30 | 25 |
- Size Measurement | - 计算工作量 | 10 | 13 |
- Postmortem & Process Improvement Plan | - 事后总结,并提出过程改进计划 | 20 | 24 |
7.小结感受:两人合作真的能够带来1+1>2的效果吗?通过这次结对合作,请谈谈你的感受和体会