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

222000310刘鑫悦 学生 2023-03-03 09:14:58
这个作业属于哪个课程<2023年福大-软件工程实践-W班社区>
这个作业要求在哪里<软件工程实践第二次作业——个人实战>
这个作业的目标<完成对澳大利亚网球公开赛相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序>
其他参考文献《构建之法》

目录

  • Gitcode项目地址
  • PSP表格
  • 解题思路描述
  • 1. 获取数据
  • 2.分析文件
  • 3.获取选手信息
  • 4.获取结果信息
  • 接口设计和实现过程
  • 关键代码展示
  • 性能改进
  • 单元测试
  • 异常处理
  • 心得体会

Gitcode项目地址

https://gitcode.net/m0_52688898/project-java

PSP表格

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

解题思路描述

经过对第二次作业的反复查看, 大致定下了项目开发的整体流程, 确定编写语言、开发环境、第三方库(fastjson)

1. 获取数据

第二次作业简单来讲是让我们使用编程语言对JSON文件进行读写操作, 从文件中获取所需的信息, 并将其输出, 所以数据文件的获取是第一步工作

①进入澳大利亚网球公开赛官网(https://ausopen.com/)

img

②打开开发者模式, 载入页面时可以看到从服务器请求的JSON文件,分别搜索players与results即可找到相应的文件

img

③预览文件, 复制文件内容到相应json文件中即可完成爬取

img

④重复以上几个步骤, 将所需的数据都下载下来

2.分析文件

使用fastjson第三方库, 快速遍历解析文件

一.fastjson的简单使用_fastjson使用

3.获取选手信息

img

通过解析players.json文件, 从“players”数组 中获取 "full_name"、“gender”、“nationality” 等属性的值

4.获取结果信息

img

通过结果信息文件, 从matches中读出 "actual_start_time"

img

从"teams"中读取status为"WInner"的队伍的"team_id", 从"score" 中读取分数

然后再根据"team_id"从teams中找到相应的"team", 再从中读取player的uuid

再去players中找到相应的选手, 这一部分功能的实现是整个程序的难点

接口设计和实现过程

img

主要包含了 AOSearch类与Lib类

其中AOSearch类负责实现对命令行参数的解析与异常处理分析,并读取"input.txt文件中的内容", 对指令正确与否进行判断, 同时将正确的指令交予Lib中的方法进行处理

Lib中主要由 "doResult" 和 "doPlayers" 两个静态方法, 分别用于处理 result指令 与 players指令

关键代码展示

主函数代码

public static void main(String[] args) {

        if (args.length != 2) {
            throw new IllegalArgumentException("命令行参数需包含输入文件与输出文件且数量为2");
        }

        FileReader fr = null;
        BufferedReader br = null;

        try {
            Lib.setOutPutFile(args[1]);
            Lib.createEmptyFile();
            File f = new File(args[0]);
            try {
                fr = new FileReader(f);
            } catch (FileNotFoundException e) {
                System.out.println("输入文件未找到: " + e.getMessage());
                System.exit(0);
            }
            br = new BufferedReader(fr);

            String line = null;
            try {
                while ((line = br.readLine()) != null) {
                    line = line.trim();
                    if (!line.equals("")) {
                        String[] params = line.split(" "); // 将一行的指令分解成多个参数分析

                        if (params.length > 2) { // 指令参数数量错误
                            if (params[0].equals("result")) {
                                Lib.writeToFile("N/A\n-----\n");
                            } else {
                                Lib.writeToFile("Error\n-----\n");
                            }
                        } else if (params.length == 2) {
                            if (!params[0].equals("result")) {
                                Lib.writeToFile("Error\n-----\n");
                            } else if (!Arrays.asList(Lib.DATE).contains(params[1])) {
                                Lib.writeToFile("N/A\n-----\n");
                            } else { // 处理 result 指令
                                Lib.doResult(params[1]);
                            }

                        } else if (params.length == 1) {
                            if (params[0].equals("result")) {
                                Lib.writeToFile("N/A\n-----\n");
                            } else if (!params[0].equals("players")) {
                                Lib.writeToFile("Error\n-----\n");
                            } else { // 处理 players 指令
                                Lib.doPlayers();
                            }
                        }
                    }
                }
            } catch (IOException e) {
                System.out.println("IO读写错误:" + e.getMessage());
            }
        } finally {
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

处理指令的两个方法

// 处理 result指令
    public static void doResult(String date) throws IOException{

        if(maps.containsKey(date)){
            writeToFile(maps.get(date));
            return;
        }

        String json = getJson(PATH+ date +".json");
        JSONObject jo = JSONObject.parseObject(json);
        JSONArray matches = JSONArray.parseArray(jo.getString("matches"));
        JSONArray teamArr = JSONArray.parseArray(jo.getString("teams"));
        JSONArray players = JSONArray.parseArray(jo.getString("players"));

        StringBuilder matchInfo = new StringBuilder();
        for (Object m : matches) {
            JSONObject match = (JSONObject) m;

            // 判断是否有弃赛
            JSONObject match_status = JSONObject.parseObject(match.getString("match_status"));
            if (match_status.getString("abbr").equals("W/O")){
                matchInfo.append("W/O\n-----\n");
                continue;
            }

            // 获取比赛时间
            String time = match.getString("actual_start_time");
            matchInfo.append("time:"+time+"\n");

            // 获取参赛的两只队伍以及获胜的队伍
            JSONArray teams = JSONArray.parseArray(match.getString("teams"));
            JSONObject team1 = teams.getJSONObject(0);
            JSONObject team2 = teams.getJSONObject(1);

            JSONObject winTeam = team1.getString("status") != null ? team1 : team2;
            String team_id = winTeam.getString("team_id");

            // 根据team_id 查找获胜的队伍
            JSONObject winnerTeam = findWinnerTeam(teamArr, team_id);
            if (winnerTeam != null) {
//                System.out.println(winnerTeam.getString("players"));
                JSONArray winners = findWinner(players, winnerTeam.getString("players"));
                // 获取获胜选手名
                matchInfo.append("winTeam:");
                for (int i = 0;i < winners.size(); i++){
                    JSONObject winPlaer = winners.getJSONObject(i);
                    matchInfo.append(winPlaer.getString("short_name"));
                    if (i < winners.size() - 1)
                        matchInfo.append(" & ");
                }
                matchInfo.append("\n");
            }

            // 获取比赛分数
            JSONArray scores1 = JSONArray.parseArray(team1.getString("score"));
            JSONArray scores2 = JSONArray.parseArray(team2.getString("score"));

            matchInfo.append("score:");
            for (int i = 0; i < scores1.size(); i++) {
                JSONObject score1 = scores1.getJSONObject(i);
                JSONObject score2 = scores2.getJSONObject(i);
                matchInfo.append(score1.getString("game") + ":" + score2.getString("game"));
                if (i < scores1.size() - 1) {
                    matchInfo.append(" | ");
                }
            }
            matchInfo.append("\n-----\n");

        }
        maps.put(date,matchInfo.toString());
        writeToFile(matchInfo.toString());
    }

    // 处理 players指令
    public static void doPlayers() throws IOException{
        if(maps.containsKey("players")){
            writeToFile(maps.get("players"));
            return;
        }

        String json = getJson(PATH+"players.json");
        JSONObject jo = JSONObject.parseObject(json);
        JSONArray players = JSONArray.parseArray(jo.getString("players"));

        StringBuilder playerInfo = new StringBuilder();
        for (Object p : players) {
            JSONObject player = (JSONObject) p;
            String full_name = player.getString("full_name");
            String gender = player.getString("gender").equals("M") ? "male" : "female";
            String nationality = player.getJSONObject("nationality").getString("name");
            playerInfo.append("full_name:" + full_name + "\n");
            playerInfo.append("gender:" + gender + "\n");
            playerInfo.append("nationality:" + nationality + "\n-----\n");
        }
        maps.put("players",playerInfo.toString());
        writeToFile(playerInfo.toString());

    }

性能改进

  1. 对连续的字符串拼接采用了 StringBuilder 来加速字符串的拼接
  2. 对先前已经处理过的指令,对其输出结果进行缓存处理,下次遇到相同指令时可以直接读出
  3. 尽量减少了对程序的IO次数, 增加了程序的可读性

单元测试

设置了11个输入案例测试测试

img

覆盖率测试

img

异常处理

  1. 参数数目不匹配的异常处理

    由于用户可以自定义输入参数, 需要对输入参数进行严格的检查处理,程序中使用了try-catch进行代码检查处理,

    对于非players或result开头的指令, 将输入 Error, 而result后参数不符合要求的指令, 将输入 N/A

  2. IO异常处理

    由于程序中多次涉及文件的IO操作, 容易引发IOException, 故程序对文件的读写.关闭都做了捕获处理

心得体会

本次软工作业, 整体难道上来说难度不会太高, 尤其是在拥有第三方库帮助解析的情况下, 代码开发得到了事半功倍, 但由于有些日子没有书写Java代码, 对IO类的驾驭不够熟练, 从本次的项目开发中, 重新回忆起了过往学习的知识点。并且对于单元测试与异常处理已经PSP表格制造有了一定的初步了解
...全文
193 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复

考虑执行几万行有效指几十万行指令的情况下,程序的实现是否依然能有效执行?在这个前提下谈谈你的优化~

688

社区成员

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

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