软件工程实践第二次作业——个人实战

222000132许依红 学生 2023-03-03 16:45:10
这个作业属于哪个课程2023年福大-软件工程实践-W班
这个作业要求在哪里软件工程实践第二次作业——个人实战
这个作业的目标1.完成代码编写并进行测试。2.撰写博客。
其他参考文献Java性能优化 ; Java Gson教程Java文本逐行读取及效率对比

目录

  • 1. Gitcode项目地址
  • 2. PSP表格
  • 3. 解题思路描述
  • 3.1爬取数据
  • 3.2解析json文件
  • 3.3读写txt文件
  • 4.设计和实现过程
  • 4.1项目包含的类
  • 4.2类与主要函数
  • 4.3主要函数关系
  • 5. 关键代码展示
  • 6.性能改进
  • 7.单元测试
  • 8.异常处理
  • 9.心得体会

1. Gitcode项目地址

点击进入项目地址

2. PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3050
• Estimate• 估计这个任务需要多少时间3050
Development开发6201000
• Analysis• 需求分析 (包括学习新技术)80120
• Design Spec• 生成设计文档4060
• Design Review• 设计复审2030
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)2030
• Design• 具体设计60120
• Coding• 具体编码300500
• Code Review• 代码复审4060
• Test• 测试(自我测试,修改代码,提交修改)6080
Reporting报告6090
• Test Repor• 测试报告2030
• Size Measurement• 计算工作量1530
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划2530
合计7101140

3. 解题思路描述

3.1爬取数据

一开始并不知道怎么爬取数据,后来经过百度了解到可以利用浏览器的开发者工具进行数据爬取。
首先,进入澳大利亚网球公开赛官网,找到schedule栏,选择要爬取的赛事日期,按F12打开浏览器开发者工具,选择“网络”,等待响应,点击schedule文件名,右边会出现json格式的数据。

在这里插入图片描述

然后双击schedule文件名,会出现新页面,点击“原始数据”,选择“美化输出”,就可以把数据按美化输出后的样式保存成json文件。

在这里插入图片描述

3.2解析json文件

这次作业编码重点就是读json文件,将所需的数据输出。因为之前在学习Android时用过gson,所以我打算继续用第三方库gson来解析json文件。大概思路就是建player类,schedule类,然后用gson反序列化得到相应的对象,最后输出。但是没想到的是实际编码过程中发现json文件里数据是比较复杂的,就干脆用JsonObject和JsonArray一层一层获取所需的数据。

3.3读写txt文件

一是读输入的指令文件input.txt,打算按行读取每条指令,用String类的split函数对每条指令进行处理,然后判断指令的正确性,最后执行指令。
二是写结果文件output.txt,考虑到每条指令执行都有各自的结果,就先将结果存在一个字符串数组,最后一起写进output文件。

4.设计和实现过程

4.1项目包含的类

//主程序,包含main方法
public class AOSearch {...}
//Lib类,包含自定义函数
public class Lib {...}
//Player类,存放运动员相关信息
public class Player {...}
//Scores类,存放每个队的比赛成绩
public class Scores {...}
//Team类,存放每个队的信息
public class Team {...}

4.2类与主要函数

  • Lib类
//Lib类,包含自定义函数
public class Lib {
    //读指令文件input.txt
    public static boolean readInputTxt(String file) throws IOException {...}
    //判断每条指令的正确性
    public static String isRightInstruction(String s) {...}
    //判断result指令后日期是否正确
    public static boolean isRightDate(String s) {...}
    //执行指令
    public void runInstruction() throws IOException {...}
    //读取json文件
    public String readJson(String s) throws IOException {...}
    //获取运动员信息
    public void getPlayers(String s) {...}
    //获取赛事信息
    public void getSchedule(String s) {...}
    //获取胜利队伍的成员信息
    public void getWinPlayers(JsonObject jsonObject,ArrayList<String> winteam,HashMap<String, ArrayList> Sites) {...}
    //按格式输出时间及对应的比赛队伍成绩
    public void showScheduleForm(ArrayList<Team> tm,ArrayList<String> time,ArrayList<String> winteam,HashMap<String, ArrayList> Sites) {...}
    //获取要写入文件的结果
    public ArrayList<String> getResults() {...}
    //将结果写入文件
    public void writeToFile(String file) throws IOException {...}
}
  • Player类
public class Player {
    private String full_name; //全名
    private String gender; //性别
    private String nationality; //国籍
    public Player(String s1,String s2,String s3){
        full_name=s1;
        gender=s2;
        nationality=s3;
    }
    @Override
    public String toString() {...}
    ...//及set、get方法
  • Scores类
public class Scores {
    private String set,game; //场次、得分
    private boolean winner; //是否胜利
    public Scores(String set,String game,boolean winner){
        this.set=set;
        this.game=game;
        this.winner=winner;
    }
    ...//及set、get方法
  • Team类
public class Team {
    private String status=null; //状态
    private String team_id; //队名id
    private ArrayList<Scores> scoresArrayList; //成绩
    public Team(){
        scoresArrayList=new ArrayList<Scores>();
    }
    ...//及set、get方法

4.3主要函数关系

  • (1)AOSearch.main函数
    调用lib.readInputTxt() 函数读取输入文件里的指令
    调用lib.runInstruction() 函数执行指令
    调用lib.writeToFile() 函数将结果写入输出文件
  • (2)Lib.isRightInstruction函数
    调用lib.isRightDate() 函数判断赛事日期是否正确
  • (3)Lib.runInstruction函数
    调用lib.isRightInstruction() 函数判断指令正误
    调用lib.readJson() 函数读取json文件
    调用lib.getPlayers() 函数获取运动员信息
    调用lib.getSchedule() 函数获取赛事信息
  • (4)Lib.getSchedule函数
    调用lib.getWinPlayers() 函数获取胜利队的成员名
    调用lib.showScheduleForm() 函数按格式输出赛事信息

5. 关键代码展示

1、我觉得本次作业关键点是对于赛事结果的获取,里面的细节点有这些:

  • 获胜队成员的名字缩写查找:status:winner-->获胜队伍id-->成员id-->成员名字缩写
  • 两个队伍成绩的获得,并且按场次顺序输出各自成绩
  • 得到数据后,按要求格式整理数据
//获取胜利队成员名字
   public void getWinPlayers(JsonObject jsonObject,ArrayList<String> winteam,HashMap<String, ArrayList> Sites) {
       //取获胜队的成员
       JsonArray teamArray = jsonObject.getAsJsonArray("teams");
       for (String s : winteam) {
           for (JsonElement ta : teamArray) {
               JsonObject jsonObject1 = ta.getAsJsonObject();
               String uuid = jsonObject1.get("uuid").getAsString();
               //判断是否是获胜队
               if (uuid.equals(s)) {
                   //取出成员编号
                   JsonArray memberArray = jsonObject1.get("players").getAsJsonArray();
                   ArrayList<String> members = new ArrayList<String>();
                   for (JsonElement ma : memberArray) {
                       members.add(ma.getAsString());
                   }
                   Sites.put(uuid, members);
               }
           }
       }
       //在player数组找成员名字
       JsonArray playerArray = jsonObject.getAsJsonArray("players");
       ArrayList tmp;
       //player
       for (JsonElement pa : playerArray) {
           JsonObject jsonObject1 = pa.getAsJsonObject();
           String playeruuid = jsonObject1.get("uuid").getAsString();
           for (String i : Sites.keySet()) {
               tmp = Sites.get(i);
               for (int j = 0; j < tmp.size(); j++) {
                   //找到名字就替换成员编号
                   if (tmp.get(j).equals(playeruuid)) {
                       tmp.set(j, jsonObject1.get("short_name").getAsString());
                   }
               }
               Sites.replace(i, tmp);
           }
       }
   }

以上获取成员名字缩写思路就是:将获胜队伍id与该队伍成员id用HashMap的方式进行匹配,然后再取查询成员id对应得名字缩写,替换id,目的是为了队伍id队伍成员名字缩写相匹配。

 public void showScheduleForm(ArrayList<Team> tm,ArrayList<String> time,ArrayList<String> winteam,HashMap<String, ArrayList> Sites) {
      int p = 0;
      //先按时间顺序
      StringBuilder sb;
      for (int i = 0; i < time.size(); i++) {
          sb = new StringBuilder();
          if (time.get(i).equals("no")) {
              sb.append("W/O\n-----\n");
          } else {
              sb.append("time:").append(time.get(i)).append("\nwinner:");
              //找胜利队成员
              int b = 0;
              if (Sites.get(winteam.get(i)) != null) {
                  for (int m = 0; m < Sites.get(winteam.get(i)).size(); m++) {
                      sb.append(Sites.get(winteam.get(i)).get(m));
                      if (b != Sites.get(winteam.get(i)).size() - 1) {
                          sb.append(" & ");
                          b++;
                      }
                  }
                  sb.append("\nscore:");
                  int m = 0;
                  //按2个队伍一组,输出2队之间成绩
                  for (int j = 0; j < tm.get(p).getScore().size(); j++) {
                      sb.append(tm.get(p).getScore().get(j)).append(":").append(tm.get(p + 1).getScore().get(j));
                      if (m != tm.get(p).getScore().size() - 1) {
                          sb.append(" | ");
                          m++;
                      }
                  }
                  sb.append("\n-----\n");
                  p = p + 2;
              }
              results.add(sb.toString());
          }
      }
  }

以上按格式输出赛事的思路就是:首先,已经提前把时间和获胜队伍id分别存储在字符串数组里,这样就可以输出格式前两行的time和winner,对于特殊情况“弃赛”就直接输出“W/O”;接下来,先前读取赛事时把所有队伍id也存储在字符串数组里,就是按两个队伍为一组,将成绩根据场次顺序输出来。这样一个时间段的比赛情况就按格式整理好了。

6.性能改进

1、在循环输出赛事结果时,字符串连接时使用StringBuilder/StringBuffer的append方法代替字符串的“+”号连接,提高效率。
2、在循环遍历JsonArray时不要不断创建JsonObject对象引用,节省内存空间,如:

img

7.单元测试

1、部分测试代码

  • 判断指令是否正确
@Test
    void isRightInstructionTest() { //判断指令是否正确
        assertEquals("players",Lib.isRightInstruction("players"));
        assertEquals("Error",Lib.isRightInstruction("Player"));
        assertEquals("N/A",Lib.isRightInstruction("result"));
        assertEquals("Error",Lib.isRightInstruction("result0116"));
        assertEquals("N/A",Lib.isRightInstruction("result 0133"));
        assertEquals("N/A",Lib.isRightInstruction("result sss"));
        assertEquals("N/A",Lib.isRightInstruction("result 117"));
        assertEquals("0116",Lib.isRightInstruction("   result   0116"));
        assertEquals("Q2",Lib.isRightInstruction("result Q2"));
        assertEquals("Error",Lib.isRightInstruction("re"));
        assertEquals("N/A",Lib.isRightInstruction(" result players"));
    }
  • 测试获取Player的结果是否为空
    @Test
    void getPlayerTest() throws IOException {
        Lib lib1=new Lib();
        lib1.getPlayers(lib1.readJson("players"));
        assertNotNull(lib1.getResults());
    }

2、单元测试覆盖率

在这里插入图片描述

8.异常处理

1、命令行参数个数的错误

在这里插入图片描述

2、文件不存在

在这里插入图片描述

3、文件读写的异常

在这里插入图片描述


在这里插入图片描述

9.心得体会

  • 在编码过程中要思路清晰,因为用旧数据格式解析复杂json数据时我是层层循环遍历获取,容易出错,然后就会卡壳,又要重新理一遍思路。
  • 第一次用gitcode管理代码还不太习惯,但用的时候发现了它的好处:当代码改动多次后,效果不如之前还可以迅速找回原来的代码。
  • 在做这次作业过程中,学习了爬取数据,单元测试和性能优化等,这些东西其实之前都没有用过,只有到实际运用时才会去学这些,也就是边做边学,希望自己今后能提前去学一些未来可能会用上的知识或技术,不要等到要用的时候才狂补,耗时耗精力,这就是“磨刀不误砍柴工”。
...全文
262 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
助教-张思锐 助教 2023-03-11
  • 打赏
  • 举报
回复

有所准备才能有所收获

685

社区成员

发帖
与我相关
我的任务
社区描述
2023年福州大学软件工程实践课程W班的教学社区
软件工程团队开发软件构建 高校 福建省·福州市
社区管理员
  • FZU_SE_teacherW
  • aboutazhang
  • 郭渊伟
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧