222200110刘炳麟_软件工程第二次作业

222200110刘炳麟 2024-09-10 16:38:23
这个作业属于哪个课程2401_CS_SE_FZU
这个作业要求在哪里软件工程第二次作业
这个作业的目标实现一个能够对国家排名及奖牌个数统计的控制台程序,封装与设计接口,单元与环回测试,git的使用。
其他参考文献

目录

  • Gitcode项目地址
  • PSP表格
  • 解题思路描述
  • 数据的爬取
  • 接口设计和实现过程
  • Main函数
  • RankRead类
  • Medal类
  • 关键代码展示
  • 功能一:对于奖牌榜使用了单独定义类Medal进行数据的对象化并利用rank容器存储
  • 功能二:List容器进行存储
  • 性能改进
  • 单元测试
  • 输出所有选手信息
  • 输出每日赛程
  • 多行输入
  • 日期不在奥运会期间
  • 多个无法识别的指令
  • 多个有效指令
  • 混合指令
  • 心得体会

Gitcode项目地址

我的fork仓库

PSP表格

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

解题思路描述

数据的爬取

巴黎奥运会奖牌榜网站利用配置好的爬虫插件进行奖牌和项目的内容爬取,得到两个.TXT文件

img

img

并进行简单的数据处理如更改为英文简写、段落处理等,对比赛项目文件进行了分隔符处理以便于编写的程序对于文档的读取

接口设计和实现过程

Main函数

OlympicSearch通过对TXT数据处理,通过main函数的args传入命令行参数。读入两个参数,分别作为输入和输出文件,对于无法识别的输入会报错,通过writeOutput函数输出至output文件中

RankRead类

通过字符串函数读取奖牌榜中的奖牌数,并作为数据rank容器传递给Medal类

Medal类

建立奖牌对象,通过get() RankRead的传递值进行奖牌数据的存储

关键代码展示

功能一:对于奖牌榜使用了单独定义类Medal进行数据的对象化并利用rank容器存储

 public Medal(int rank, String country, int gold, int silver, int bronze, int total)
{
    this.rank = rank;
    this.country = country;
    this.gold = gold;
    this.silver = silver;
    this.bronze = bronze;
    this.total = total;
}
public Medal(){}

// Getters and Setters
public int getRank() {
    return rank;
}

public void setRank(int rank) {
    this.rank = rank;
}

public String getCountry() {
    return country;
}

public void setCountry(String country) {
    this.country = country;
}

public int getGold() {
    return gold;
}

public void setGold(int gold) {
    this.gold = gold;
}

public int getSilver() {
    return silver;
}

public void setSilver(int silver) {
    this.silver = silver;
}

public int getBronze() {
    return bronze;
}

public void setBronze(int bronze) {
    this.bronze = bronze;
}

public int getTotal() {
    return total;
}

public void setTotal(int total) {
    this.total = total;
}

@Override
public String toString() {
    return  rank +'\t'+
            '\t' + country +
            "\t\t\t" + gold +
            '\t' + silver +
            '\t' + bronze +
            '\t' + total;
}

使用RankRead类进行.TXT文本文件的处理

public class RankRead {
public List<Medal> ranks;

public RankRead(String filePath) {
    this.ranks = new ArrayList<>();
    readRankFile(filePath);
}

private void readRankFile(String filePath) {
    try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
        String line;
        while ((line = reader.readLine()) != null) {
            parseLine(line);
        }
    } catch (IOException e) {
        e.printStackTrace();//读Rank文件
    }
}

private void parseLine(String line) {
    String[] parts = line.split("\t");
    if (parts.length == 6) {
        int rank = Integer.parseInt(parts[0]);
        String country = parts[1];
        int gold = Integer.parseInt(parts[2]);
        int silver = Integer.parseInt(parts[3]);
        int bronze = Integer.parseInt(parts[4]);
        int total = Integer.parseInt(parts[5]);

        Medal rankObj = new Medal(rank, country, gold, silver, bronze, total);
        ranks.add(rankObj);
    }
}

public List<Medal> getRanks() {
    return ranks;
}

public void printRanks() {
    for (Medal rank : ranks) {
        System.out.println(rank);
    } //将奖杯排行打印出来
}
                   }

功能二:List容器进行存储

List容器存储比赛信息

    List<String[]> matches = new ArrayList<>();
    try (BufferedReader reader = new BufferedReader(new FileReader(matchFile))) {
        String line;
        while ((line = reader.readLine()) != null) {
            String[] parts = line.split("\t");
            String fileDate = extractDate(parts[0]);
            if (fileDate.equals(date)) {
                matches.add(parts);
            }
        }
    }// 读取比赛信息

    for (String[] match : matches) {
        String formattedName = formatMatchName(match[3]);
        writer.write("time:" + match[1] + "\nsport:" + match[2] + "\nname:" + formattedName + "\nvenue:" + match[4] + "\n-----\n");
    }
    if (matches.isEmpty()) {
        writer.write("N/A\n-----\n");
    }
}// 写入比赛信息



private static String extractDate(String input) {
    try {
        // 分割输入字符串,使用制表符('\t')
        String[] parts = input.split("\t");
        if (parts.length >= 1) {
            // 提取日期时间部分
            String dateTimePart = parts[0];


            return extractMonthAndDay(dateTimePart);
        } else {
            // 如果没有足够的部分,则返回默认值
            System.err.println("Input does not contain a valid date: " + input);
            return "0000";
        }
    } catch (Exception e) {
        // 如果解析失败,返回默认值或抛出异常
        System.err.println("Invalid date format: " + input);
        return "0000";
    }
}// 提取日期

public static String extractMonthAndDay(String dateString) {
    // 定义输入和输出的日期格式
    SimpleDateFormat inputFormat = new SimpleDateFormat("MM月dd日");
    SimpleDateFormat outputFormat = new SimpleDateFormat("MMdd");

    try {
        // 解析输入的日期字符串
        Date date = inputFormat.parse(dateString);
        // 使用新的格式化器格式化日期
        return outputFormat.format(date);
    } catch (ParseException e) {
        // 处理解析错误的情况
        e.printStackTrace();
        return null;
    }
}// 提取月份和日期

private static String formatMatchName(String name) {
    if (name.contains(":")) {
        String[] teams = name.split(":");
        return teams[0].trim() + " VS " + teams[1].trim();
    } else {
        return name.trim();
    }
    }// 格式化比赛名称

性能改进

主要存在的问题是IO时间长,代码覆盖范围小,适应性差

单元测试

输出所有选手信息

total

img

输出每日赛程

schedule 0803

img

多行输入

total
schedule 0803

img

日期不在奥运会期间

schedule 0823

img

多个无法识别的指令

totoI
schedule 0817

img

多个有效指令

total
schedule 0804
total

混合指令

total
totol
schedule 0804
schedule 0823

img

心得体会

1. 模块化设计
独立性:将核心功能(如countChar)封装在独立的Core类中,保证其独立于具体的应用程序界面或其他功能模块。这种设计使得核心功能可以在多个环境中复用,而不依赖于特定的用户界面或外部系统。
职责分离:将计算逻辑和界面逻辑分开,有助于简化每个模块的设计和维护。这种方式使得在未来的需求变更或扩展中,只需要对特定模块进行调整,而不会影响到其他模块。
2. 清晰的接口设计
简洁明确:API接口应尽量简洁、明确。例如,countChar(File file)函数仅接受一个文件对象作为输入,返回一个整数结果。这种设计使得接口的使用和理解变得直观。
错误处理:函数设计时需要考虑错误处理,例如处理文件读取过程中可能出现的IOException。在真实世界的应用中,适当的异常处理和错误信息反馈对用户体验至关重要。
3. 单元测试
测试覆盖:编写单元测试对核心功能进行验证,可以保证核心模块的正确性。CoreTest类中通过JUnit测试countChar方法的功能,确保其能够正确地计算文件中的字符数。这是软件开发中的良好实践,能够发现并修复潜在的问题。
隔离测试环境:使用临时文件进行测试,避免对真实数据的干扰。这样可以确保测试是独立的,不会因为文件的状态而受到影响。
4. 易于维护和扩展
模块化的好处:通过将核心功能和用户界面逻辑分开,系统的维护和扩展变得更加容易。例如,如果未来需要在不同平台(如移动应用或Web应用)上使用相同的核心逻辑,只需在各个平台上适配接口即可。
接口的灵活性:设计时考虑到接口的扩展性和灵活性。例如,Core类可能需要添加更多功能或支持更多文件格式,只需扩展核心功能而无需重写用户界面部分。
5. 文档和注释
清晰的文档:为了方便其他开发人员使用和维护代码,提供详细的文档和注释是必要的。每个函数的用途、参数说明、返回值和异常情况都应明确记录,以便团队成员能够快速理解和使用这些功能。
维护说明:文档中应包括如何添加新功能或修改现有功能的指导,帮助未来的开发和维护工作。

...全文
96 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

111

社区成员

发帖
与我相关
我的任务
社区描述
202401_CS_SE_FZU
软件工程 高校
社区管理员
  • FZU_SE_TeacherL
  • 言1837
  • 防震水泥
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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