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

062000224刘泓 学生 2023-03-02 09:22:47
这个作业属于哪个课程2023年福大-软件工程实践-W班
这个作业要求在哪里软件工程实践第二次作业——个人实战
这个作业的目标完成对澳大利亚网球公开赛相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序
其他参考文献

目录

  • GitCode 项目地址
  • PSP 个人开发刘流程表
  • 解题思路描述
  • 开发语言选择
  • 数据爬取
  • 需求分析
  • 工具选择
  • 接口设计和实现过程
  • 关键代码展示
  • 性能改进
  • 单元测试
  • 异常处理
  • 心得体会

GitCode 项目地址

Project-Java

PSP 个人开发刘流程表

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

解题思路描述

开发语言选择

在拿到题目之后,我细致阅读。

我了解到此次实践希望我们能开发一款能处理从网络上爬取的 JSON 数据,并能按照用户的需求格式化输出到 文件控制台程序

开发语言可以从 C++ 和 Java 中择一。考虑到 Java 有 GSON 等较为成熟的 JSON 解析工具,我选择使用 Java 完成本次作业。

数据爬取

通过浏览澳大利亚网球公开赛网站的请求记录,我发现当访问 https://ausopen.com/schedule 某个日期的页面,会向服务器的 https://prod-scores-api.ausopen.com/year/2023/period/MD/day/1/schedule 接口请求赛程数据的 JSON 数据。

其中 /day/1/schedule 的数字 1 即为 Day 1 的比赛的数据。

通过编写简单的 Bash 脚本,我使用 wget 将 16 天的赛程数据爬取下来。

对于预选赛的数据,可以使用同样的方法爬取。

需求分析

程序的输入为一个文本文件,输出也为一个文本文件。

程序读取输入文件中的指令,根据指令的要求在爬取数据中筛选出部分数据,格式化后输出至输出文件。

需要实现的指令有:

  • players 输出所有选手信息
  • result 01xx 输出正式赛每日结果
  • result Qx 输出资格赛结果

程序需要具有能从文件中读取并解析 JSON 数据的能力,且程序需要有能从 JSON 中提取对应数据的能力。

程序需要能作为模块被引用,因此需要将实现每个指令对应的函数包装为接口。

在程序编写完成后,应对程序进行全面的单元测试。

在所有功能写作完成后,需要进行性能测试,尽可能提高性能。

工具选择

对于文件读取,我选择使用 Java 内置的 FileStream 和 BufferedReader 包;

对于 JSON 解析,我选择使用曾经使用过的、较为熟悉的 GSON 包;

对于单元测试,我选择了 Java 社区较为主流的 JUnit 5 包。

对于性能改进方面,我选择使用 IDEA 自带的 InteliJ Profiler 分析程序的性能。

接口设计和实现过程

考虑到程序的可复用性,我采用了工厂方法设计模式,设计了名为 OutputDataFactory 的接口,内含 createOutputData 函数生产产品。 由 PlayerDataFactoryMatchDataFactory 继承。

产品则设计了 OutputData 接口,内含 formatOutput 将数据格式化为字符串输出。 由 PlayerInfoDataMatchResultData 继承。这些类和接口都封装在名为 Core 的类中,作为程序的核心类库。

在实现功能时,仅需创建 OutputDataFactory 的子类,并执行 createOutputData 获得产品,对产品执行 formatOutput 即可获取格式化后的字符串数据。

而读取输入文件、写入输出文件、执行命令、清空输入文件等功能则封装在名为 Utils 的类中,作为程序的工具类库。

项目流程图:

img

关键代码展示

产品接口于两个产品类。

public interface OutputData {
    String formatOutput();
}

/***
 * This is a class for storing the player data.
 */
public static class PlayerInfoData implements OutputData {
    public String fullName;
    public String gender;
    public String nationality;

    @Override
    public String formatOutput() {
        ......
    }
}

/***
 * This is a class for storing the match result data.
 */
public static class MatchResultData implements OutputData {
    public String time;
    public String winner;
    public String score;

    @Override
    public String formatOutput() {
        ......
    }
}

工厂接口与两个工厂类。

public interface OutputDataFactory {
    Vector<OutputData> createOutputData(Utils.InputCommand inputCommand, String inputFileFolder) throws IOException;
}

public static class PlayerInfoDataFactory implements OutputDataFactory {
    /***
     * This method get info of all players and return as Object.
     * @param inputCommand The input command.
     * @param inputFileFolder The folder of the player info file.
     * @return The info of all players.
     */
    @Override
    public Vector<OutputData> createOutputData(Utils.InputCommand inputCommand, String inputFileFolder) throws IOException {
        ......
    }
}

public static class MatchResultDataFactory implements OutputDataFactory {
    /***
     * This method get result of match and return as Object.
     * @param inputCommand The input command.
     * @param inputFileFolder The folder of the match result file.
     * @return The result of the match.
     */
    public Vector<OutputData> createOutputData(Utils.InputCommand inputCommand, String inputFileFolder) throws IOException {
        ......
    }
}

读取文件内容(使用 Apache Commons IO)

public static String readContentFromFile(String path) throws IOException {
    LineIterator it = FileUtils.lineIterator(new File(path), "UTF-8");
    StringBuilder content = new StringBuilder();
    try {
        while (it.hasNext()) {
            String line = it.nextLine();
            content.append(line);
        }
    } finally {
        LineIterator.closeQuietly(it);
    }
    return content.toString();
}

执行命令前使用正则表达式检查输入的命令是否合法。

public static void executeCommand(InputCommand inputCommand, String inputFileFolder, String outputFilePath) {
    // Check whether the command is valid.
    if (!Objects.equals(inputCommand.command, "players") && !Objects.equals(inputCommand.command, "result")) {
        ......
    }
    if (Objects.equals(inputCommand.command, "result")) {
        // Check whether the argument is valid.
        Pattern pattern1 = Pattern.compile("01[0-9]{2}");
        Matcher matcher1 = pattern1.matcher(inputCommand.arg);
        Pattern pattern2 = Pattern.compile("Q[1-4]");
        Matcher matcher2 = pattern2.matcher(inputCommand.arg);
        if (matcher1.find()) {
            // Is 01xx type arg.
            int dateNum = Integer.parseInt(inputCommand.arg);
            if (dateNum < 116 || dateNum > 129) {
                ......
            }
        } else if (matcher2.find()) {
            // Is Qx type arg.
            int quarterNum = Integer.parseInt(inputCommand.arg.substring(1));
            if (quarterNum < 1 || quarterNum > 4) {
                ......
            }
        } else {
            // Is not 01xx or Qx type arg.
            ......
        }
    }
    // Execute command
    ......
}

性能改进

使用 IDEA 的 InteliJ Profiler 工具分析程序的性能,可以发现 readContentFromFile 函数中通过 BufferReader 读取 JSON 文件的步骤花费了较多的时间。

通过将 BufferedReader 更换为 Apache Commons IO 的 FileUtils 之后,可以观测到主线程消耗的时间缩短了约 25%。

修改前性能:

img

修改后性能:

img

单元测试

我设计了 13 组单元测试,对 Lib 中每个函数都进行了包括正确输入和错误输入的测试。

测试结果如下:

img

Lib 库方法覆盖率达到 100%,行覆盖率达到 83%。

覆盖率截图:

img

异常处理

对文件打开失败、找不到文件等异常做了异常处理。

心得体会

通过此次作业,我复习了一下 Java 的语法,发现没忘记太多。

我先尝试使用接口方式设计 Lib 的框架,在编写部分函数后发现重复的代码很多,也没有满足开闭原则。正好那天设计模式课上讲到了工厂模式,我一看,这不是我想要的吗。深知 Java 喜欢用这种“鬼方法”,我何不自己也尝试一下呢。

浅尝之后发现确实能复用很多代码,添加新功能的时候只需要编写对应的工厂类和产品类,目标很明确。缺点是要建很多类,但有 IDE 和 AI 的帮忙之下问题不是很大。

这也是我第一次写这么多文档。Javadoc 确实能“逼迫”着我把文档写清楚,为后面接盘的人带来福音(笑)。

...全文
215 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
郭渊伟 助教 2023-03-11
  • 打赏
  • 举报
回复

作业完成的很好,美中不足就是异常处理部分,太过于简略

688

社区成员

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

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