688
社区成员
发帖
与我相关
我的任务
分享| 2023春软件工程实践 | 2023年福大-软件工程实践-W班社区-CSDN社区云 |
|---|---|
| 这个作业要求在哪里 | 软件工程实践第二次作业——个人实战-CSDN社区 |
| 这个作业的目标 | 根据命令行输入,输出2023年澳大利亚网球公开赛的选手信息和比赛结果。 |
| 其他参考文献 | 构建之法 |
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 15 | 15 |
| • Estimate | • 估计这个任务需要多少时间 | 440 | 515 |
| Development | 开发 | 440 | 515 |
| • Analysis | • 需求分析 (包括学习新技术) | 5 | 15 |
| • Design Spec | • 生成设计文档 | 15 | 15 |
| • Design Review | • 设计复审 | 15 | 10 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 5 | 5 |
| • Design | • 具体设计 | 120 | 120 |
| • Coding | • 具体编码 | 60 | 65 |
| • Code Review | • 代码复审 | 35 | 35 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 90 | 145 |
| Reporting | 报告 | 60 | 65 |
| • Test Repor | • 测试报告 | 5 | 10 |
| • Size Measurement | • 计算工作量 | 5 | 5 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 15 | 15 |
| 合计 | 455 | 530 |
任务一的数据选手数据下载与群文件,任务二的赛事结果数据爬取自官网,打开AOS官网,找到result页面,打开浏览器开发者模式的网络模块,再点击对应的比赛日,从开发者工具中找到result文件,将其另存为json。
先采用文件输入流打开json文件并转存为字符串
可以采用第三方库Gson的fromjson来将json转存的字符串转换成实体类,为了能够对json的数据的字段进行查找,所以将json转成Map<String,Object>,然后逐层用get方法获得所需字段。
由于比赛的选手和场数数量庞大,反复读取json文件效率低效,又因为需要通过时间反复查找对应比赛日的结果集,通过选手id找出选手的名字缩写,所以设计map结构来存取信息备用。
同时赛事结果文件中只有队伍id,而队伍选手id列表存在与players.json,为了方便查找获胜选手的名字缩写需要建立team_id到选手id的映射。
当程序需要打印比赛选手信息时,直接打印选手map的values();
需要打印比赛日或者赛季信息时,初次打印先解析json并放入map,再从map取出
...
...4.1 主要类
//程序入口,主函数接收输入输出文件的路径
public class AOSSearch {}
//工具类,负责代码运行逻辑
public class Lib {}
//实体类,存放比赛结果信息
class AOSGame {}
//实体类,存放选手信息
class AOSPlapyer {}
public class Lib {
//存放选手信息
public static Map<String,AOSPlayer> Player= new HashMap<>();
//存放每一天的赛程结果
public static Map<String,ArrayList<AOSGame>> Game=new HashMap<>();
//存放每一行的指令
public static ArrayList<String> orders=new ArrayList<>();
//存放队伍id到选手id列表的映射
public static Map<String,List<String>> Team2Player= new HashMap<>();
//存放选手和赛程的文件位置
public static final String PLAYERPATH ="src\\data\\players.json";
public static final String GAMEERPATH= "src\\data\\schedule\\";
//读取input中的指令并存储到orders数组中
public static void read(String inputFilePath) throws IOException{...}
//读取json文件中的数据并返回对应字符串
public static String readJson(String jsonFilePath) throws FileNotFoundException,IOException{...}
//将从json文件中读取出的字符串进一步处理并存储到Player中
public static void readPlayer() throws IOException{...}
//从Team2Player中找到获胜选手缩写的拼接
public static String getWinner(String team_id) throws IOException{
//将从json文件中读取出的字符串进一步处理并存储到Game中
public static void readGame(String date) throws IOException{...}
//从map中解析出结果对象
public static AOSGame getAOSGame(Map<String,Object> a) throws IOException{...}
//将选手信息输出到对应的文件
public static void writePlayers() throws IOException{...}
//将赛程结构输出到对应的文件
public static void writeGame(String date) throws IOException {...}
//将无法输出的情况输出
public static void writeError(String message) throws IOException{...}
//对于程序是否在比赛日中
public static boolean hasDate(String date){...}
}
public class AOSSearch {
//捕获各类异常
public static void main(String[] args) {
try {
Lib.read(args[0]);
Lib.write(args[1]);
}
catch (FileNotFoundException fileNotFoundException){
System.out.println("文件不存在");
}
catch (IOException ioException){
System.out.println("文件读写失败");
}
}
}

public static String readJson(String jsonFilePath) throws FileNotFoundException,IOException{
StringBuilder data=new StringBuilder();
String tem;
InputStream file;
jsonFilePath=System.getProperty("user.dir")+File.separator+jsonFilePath;
file=new FileInputStream(jsonFilePath);
BufferedReader reader=new BufferedReader(new InputStreamReader(file,StandardCharsets.UTF_8));
while((tem=reader.readLine())!=null){
data.append(tem);
}
reader.close();
return data.toString();
}
//将从json文件中读取出的字符串进一步处理并存储到Player中
public static void readPlayer() throws IOException{
String json=readJson(PLAYERPATH);
Gson gson=new Gson();
Map<String,Object> data=gson.fromJson(json,Map.class);
List<Map<String,Object>> PlayerList=(List<Map<String,Object>>) data.get("players");
for(Map<String,Object> m:PlayerList){
AOSPlayer o=new AOSPlayer((String)m.get("full_name"),(String)m.get("gender"),((Map<String,String>)m.get("nationality")).get("name"),(String) m.get("uuid"),(String) m.get("short_name"));
Player.put((String) m.get("uuid"),o);
}
List<Map<String,Object>> TeamList=(List<Map<String,Object>>) data.get("teams");
for(Map<String,Object> t:TeamList){
List<String> pl = (List<String>)t.get("players");
String tid = (String)t.get("uuid");
Team2Player.put(tid,pl);
}
}
//将从json文件中读取出的字符串进一步处理并存储到Game中
public static void readGame(String date) throws IOException{
ArrayList<AOSGame> s=new ArrayList<>();
String json=readJson(GAMEERPATH+date+".json");
Gson gson=new Gson();
Map<String,Object> map=gson.fromJson(json,Map.class);
List<Map<String,Object>> matches=(List<Map<String,Object>>) map.get("matches");
for(Map<String,Object> a : matches)
s.add(getAOSGame(a));
Game.put(date,s);
} public static AOSGame getAOSGame( Map<String,Object> a) throws IOException{
String time = (String) a.get("actual_start_time");
String winner;
Map<String,String> stats =(Map<String,String>) a.get("match_status");
//比赛有人弃权
if(stats.get("abbr").equals("W/O"))
return new AOSGame();
List<Map<String,Object>> teams = (List<Map<String,Object>>) a.get("teams");
Map<String,Object> t1 = teams.get(0);
Map<String,Object> t2 = teams.get(1);
List<Map<String,String>> s1 =(List<Map<String,String>>) t1.get("score");
List<Map<String,String>> s2 =(List<Map<String,String>>) t2.get("score");
String score="";
for(int i =0;i<s1.size();i++){
score+=(s1.get(i).get("game")+":"+s2.get(i).get("game"))+" | ";
}
score=score.trim();
score=score.substring(0,score.length() - 1);
if(t1.get("status")!=null)
winner=getWinner((String) t1.get("team_id"));
else
winner=getWinner((String) t2.get("team_id"));
return new AOSGame(winner,score,time);
}
//从map中解析出结果对象
public static AOSGame getAOSGame( Map<String,Object> a) throws IOException{...}
public static void write(String outputFilePath) throws IOException{
FileOutputStream file=new FileOutputStream(outputFilePath,false);
readPlayer();
writer=new BufferedWriter(new OutputStreamWriter(file,StandardCharsets.UTF_8));
for(String o:orders){
o=o.trim();
if(o.equals("")){
continue;
}
String[] tem=o.split("\\s+");
if(tem.length==0){
continue;
}
if(tem[0].equals("players")){
if(tem.length==1){
writePlayer();
}
else{
writeError("Error");
}
}
else if(tem[0].equals("result")){
if(tem.length==2&&hasDate(tem[1])){
writeGame(tem[1]);
}
else {
writeError("N/A");
}
}
else{
writeError("Error");
}
}
writer.close();
//对输出文件的尾部进行处理(换行处理)
RandomAccessFile f = new RandomAccessFile(outputFilePath, "rw");
f.setLength(f.length()-1);
f.close();
}
性能改进主要从以下几点
改进前

改进后

单元测试利用Junit插件生成Lib类的测试函数,编辑10个测试用例主要利用assertEqual()来验证函数结果是否与正确结果相同。
可见除去异常处理语句,都有覆盖

在Lib中有可能出现的异常是FileNotFoundException和IOException,分别是因为文件不存在和文件流读写不成功,因为在整个运行周期有多处可能会出现这两个异常,所以我统一将Lib类产生的异常抛出,由AOSSearch处理
public static void main(String[] args) {
try {...}
catch (FileNotFoundException fileNotFoundException){...}
catch (IOException ioException){...}
}
整体设计思路清晰,赞!能否给出性能优化中改进前后的的对比图是针对多少指令行进行的测试结果?
理论知识积累丰富,能正确处理编程中的一些问题,再接再厉!