111
社区成员




这个作业属于哪个课程 | 2401_CS_SE_FZU |
---|---|
这个作业要求在哪里 | 软件工程第二次作业 |
这个作业的目标 | 实现一个能够对国家排名及奖牌个数统计的控制台程序,封装与设计接口,单元与环回测试,git的使用。 |
其他参考文献 | 无 |
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
• Estimate | • 估计这个任务需要多少时间 | 20 | 30 |
Development | 开发 | 1200 | 1570 |
• Analysis | • 需求分析 (包括学习新技术) | 200 | 300 |
• Design Spec | • 生成设计文档 | 20 | 20 |
• Design Review | • 设计复审 | 10 | 20 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
• Design | • 具体设计 | 100 | 120 |
• Coding | • 具体编码 | 700 | 900 |
• Code Review | • 代码复审 | 60 | 60 |
• Test | • 测试(自我测试,修改代码,提交修改) | 90 | 120 |
Reporting | 报告 | 50 | 70 |
• Test Repor | • 测试报告 | 20 | 30 |
• Size Measurement | • 计算工作量 | 10 | 20 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 1270 | 1660 |
在巴黎奥运会奖牌榜网站利用配置好的爬虫插件进行奖牌和项目的内容爬取,得到两个.TXT文件
并进行简单的数据处理如更改为英文简写、段落处理等,对比赛项目文件进行了分隔符处理以便于编写的程序对于文档的读取
OlympicSearch通过对TXT数据处理,通过main函数的args传入命令行参数。读入两个参数,分别作为输入和输出文件,对于无法识别的输入会报错,通过writeOutput函数输出至output文件中
通过字符串函数读取奖牌榜中的奖牌数,并作为数据rank容器传递给Medal类
建立奖牌对象,通过get() RankRead的传递值进行奖牌数据的存储
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<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
schedule 0803
total
schedule 0803
schedule 0823
totoI
schedule 0817
total
schedule 0804
total
total
totol
schedule 0804
schedule 0823
1. 模块化设计
独立性:将核心功能(如countChar)封装在独立的Core类中,保证其独立于具体的应用程序界面或其他功能模块。这种设计使得核心功能可以在多个环境中复用,而不依赖于特定的用户界面或外部系统。
职责分离:将计算逻辑和界面逻辑分开,有助于简化每个模块的设计和维护。这种方式使得在未来的需求变更或扩展中,只需要对特定模块进行调整,而不会影响到其他模块。
2. 清晰的接口设计
简洁明确:API接口应尽量简洁、明确。例如,countChar(File file)函数仅接受一个文件对象作为输入,返回一个整数结果。这种设计使得接口的使用和理解变得直观。
错误处理:函数设计时需要考虑错误处理,例如处理文件读取过程中可能出现的IOException。在真实世界的应用中,适当的异常处理和错误信息反馈对用户体验至关重要。
3. 单元测试
测试覆盖:编写单元测试对核心功能进行验证,可以保证核心模块的正确性。CoreTest类中通过JUnit测试countChar方法的功能,确保其能够正确地计算文件中的字符数。这是软件开发中的良好实践,能够发现并修复潜在的问题。
隔离测试环境:使用临时文件进行测试,避免对真实数据的干扰。这样可以确保测试是独立的,不会因为文件的状态而受到影响。
4. 易于维护和扩展
模块化的好处:通过将核心功能和用户界面逻辑分开,系统的维护和扩展变得更加容易。例如,如果未来需要在不同平台(如移动应用或Web应用)上使用相同的核心逻辑,只需在各个平台上适配接口即可。
接口的灵活性:设计时考虑到接口的扩展性和灵活性。例如,Core类可能需要添加更多功能或支持更多文件格式,只需扩展核心功能而无需重写用户界面部分。
5. 文档和注释
清晰的文档:为了方便其他开发人员使用和维护代码,提供详细的文档和注释是必要的。每个函数的用途、参数说明、返回值和异常情况都应明确记录,以便团队成员能够快速理解和使用这些功能。
维护说明:文档中应包括如何添加新功能或修改现有功能的指导,帮助未来的开发和维护工作。