688
社区成员
发帖
与我相关
我的任务
分享一、作业概览
| 这个作业属于哪个课程 | 2023年福大-软件工程实践-W班 |
|---|---|
| 这个作业要求在哪里 | 软件工程实践第二次作业——个人实战 |
| 这个作业的目标 | 1.完成对澳大利亚网球公开赛相关数据的收集 2.实现一个能够对赛事数据进行统计的控制台程序 |
| 其他参考文献 | 暂无 |
二、作业详情
https://gitcode.net/mikupi/project-java
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 20 | 30 |
| • Estimate | • 估计这个任务需要多少时间 | 1385 | 1575 |
| Development | 开发 | 600 | 660 |
| • Analysis | • 需求分析 (包括学习新技术) | 45 | 60 |
| • Design Spec | • 生成设计文档 | 30 | 45 |
| • Design Review | • 设计复审 | 10 | 15 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 10 | 5 |
| • Design | • 具体设计 | 30 | 45 |
| • Coding | • 具体编码 | 240 | 300 |
| • Code Review | • 代码复审 | 45 | 60 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 120 | 180 |
| Reporting | 报告 | 120 | 75 |
| • Test Repor | • 测试报告 | 60 | 30 |
| • Size Measurement | • 计算工作量 | 10 | 10 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 45 | 60 |
| 合计 | 1385 | 1575 |
Result和Players。然后把这些数据打包下载到本地。
org.json.simple这个jar包。players的处理,直接获取数据遍历输出即可。result的处理,略微复杂,根据json数据结构的分析,得先获取teams的编号,然后通过matches中每场比赛的数据里提取winner为true的队伍。同时在遍历的时候进行记录比分和比赛时间。其次记录下队伍编号,通过队伍的编号到teams中获取队伍的成员编号,最后通过成员编号结合players得到成员名。编号,全名,国籍,性别。拥有接口:获取数据的接口。Player类数组。实现输出所有Player和根据编号查询Player全名的功能。public class Players {
public ArrayList<Player> players;
public Players() {players = new ArrayList<Player>();}
public void add(Player p) {players.add(p);}
public int len() {return players.size();}
public String get(int i) {
String res = "";
if (this.len() > i) {
res = res + "full_name:" + players.get(i).getFullname() + "\n";
res = res + "gender:" + players.get(i).getGender() + "\n";
res = res + "nationality:" + players.get(i).getNationality();
}
return res;
}
//获取所有信息的输出结果
public String getAll() {
StringBuilder res = new StringBuilder();
if (this.len() != 0) {
for (int i = 0; i < this.len(); i++) {
if (i != 0) {
res.append("\n");
}
res.append(this.get(i)).append("\n").append("-----");
}
}
return res.toString();
}
//通过player的id去获取相应的player全名
public String getNameById(String uid) {
int l = 0;
int r = this.len() - 1;
int m;
while(l <= r) {
m = (l + r) / 2;
if (players.get(m).getUuid().compareTo(uid) < 0) {
l = m + 1;
} else if (players.get(m).getUuid().compareTo(uid) == 0) {
return players.get(m).getFullname();
} else {
r = m - 1;
}
}
return "";
}
public void Sort(){Collections.sort(this.players);}
}
public class Player implements Comparable<Player>{
private String fullname;
private String gender;
private String nationality;
private String uuid;
public Player(String fn, String g, String na, String uuid){
this.fullname = fn;
if (g.equals("M") || g.equals("m")) {
this.gender = "male";
} else {
this.gender = "female";
}
this.nationality = na;
this.uuid = uuid;
}
public String getFullname() {return this.fullname;}
public String getGender() {return this.gender;}
public String getNationality() {return this.nationality;}
public String getUuid() {return this.uuid;}
@Override
public int compareTo(Player o) {return (this.uuid).compareTo(o.uuid);}
}
队伍编号,队伍下的队员编号。拥有获取队伍信息的接口。Team类数组。实现根据队伍编号查询成员的功能。public static class Teams{
private ArrayList<Team> teams;
public Teams(){}//初始化
public void add(Team t){}//动态添加组
public String getWinnerById(String id, Players p){}//根据队伍编号,结合Player数据p得到winner的全名信息
}
public static class Team{
private String tid;//队伍编号
private ArrayList<String> playid;//成员编号
public Team(String t){}//初始化
public void add(String pid){}//动态添加成员
public String getTid(){}
public String getWinner(Players p){}//根据Player信息得到赢家的全名
}
时间,获胜者,比分,拥有获取数据的接口。Result类数组,实现输出所有的比赛结果。public static class Results{
private ArrayList<Result> results;
public Results(){}//初始化
public void add(Result t){}//动态添加结果项
public int len(){}//结果数
public String get(int i){}//某一条结果
public String getAll(){}//获取所有结果标准化输出
}
public static class Result{
private String time;
private String winner;
private String score;
public Result(String t, String w, String s){}//初始化
public String getTime(){}
public String getWinner(){}
public String getScore(){}
}
public static class Instructions{
private ArrayList<String> instructions;
public Instructions(){}//初始化
public void add(String s){}//动态添加指令
public String get(int i){}//获取某条指令
public int len(){}//指令数
public static boolean isin(String[] arr, String containValue){}//字符串处理函数
//判断指令类型输出相应处理代号
public String read(String s, String[] j) {
//处理指令
if (s.equals("players")) {
return "2";
}
if (s.length() < 7) return "0";
String front = s.substring(0, 7);
String end = s.substring(7);
if (!front.equals("result ")) {
return "0";
}
if (Lib.isin(j, end)) {
return end;
}
return "1";
}
}
json文件,提取和处理信息输出为相应的Results类实例和Players类实例。实现对input.txt文件的处理,输出为Instructions类的实例。public class MyFile {
public MyFile() {}
//根据文件解析读取输出Players
public Players ReadPlayer(String pa) throws IOException, ParseException {
Object obj = new JSONParser().parse(new FileReader(pa));
JSONObject js = (JSONObject) obj;
JSONArray players_arr = (JSONArray) js.get("players");
Players players = new Players();
int players_len = players_arr.size();
for (int i = 0; i < players_len; i++) {
JSONObject t = (JSONObject) players_arr.get(i);
players.add(parsePlayer(t));
}
return players;
}
//将获取的数据提取为Player对象
private static Player parsePlayer(JSONObject obj) {
String full_name = (String) obj.get("full_name");
String gender = (String) obj.get("gender");
JSONObject nationality = (JSONObject) obj.get("nationality");
String nationality_name = (String) nationality.get("name");
String uuid = (String) obj.get("uuid");
return new Player(full_name, gender, nationality_name, uuid);
}
//读取指令文件,拆分为指令列
public Instructions ReadInput(String pa) {
Instructions in = new Instructions();
File file = new File(pa);
BufferedReader reader = null;
String temp = null;
int line = 1;
try {
reader = new BufferedReader(new FileReader(file));
while ((temp = reader.readLine()) != null) {
in.add(temp);
line++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return in;
}
//根据文件解析读取输出Results
public Results ReadResult(String pa) throws IOException, ParseException {
Players p = ReadPlayer(pa);
p.Sort();
Object obj = new JSONParser().parse(new FileReader(pa));
JSONObject js = (JSONObject) obj;
JSONArray match_arr = (JSONArray) js.get("matches");
JSONArray team_arr = (JSONArray) js.get("teams");
int team_arr_len = team_arr.size();
Teams teams = new Teams();
for (int i = 0; i < team_arr_len; i++) {
JSONObject t = (JSONObject) team_arr.get(i);
teams.add(parseTeam(t));
}
teams.Sort();
int match_arr_len = match_arr.size();
Results results = new Results();
for (int i = 0; i < match_arr_len; i++) {
JSONObject t = (JSONObject) match_arr.get(i);
JSONObject iswo = (JSONObject) t.get("match_status");
String abbr = (String) iswo.get("abbr");
if (abbr.equals("W/O")) {
results.add(new Result("", "", "", true));
continue;
}
String time = (String) t.get("actual_start_time");
JSONArray ts = (JSONArray) t.get("teams");
String win_tid = "";
String score = "";
JSONObject t1 = (JSONObject) ts.get(0);
JSONObject t2 = (JSONObject) ts.get(1);
JSONArray t1_s = (JSONArray) t1.get("score");
JSONArray t2_s = (JSONArray) t2.get("score");
int wincount = 0;
for (int j = 0; j < t1_s.size(); j++) {
JSONObject t1_j = (JSONObject) t1_s.get(j);
JSONObject t2_j = (JSONObject) t2_s.get(j);
Boolean iswinner1 = (Boolean) t1_j.get("winner");
if (iswinner1) {
wincount++;
} else {
wincount--;
}
String s_1 = (String) t1_j.get("game");
String s_2 = (String) t2_j.get("game");
if (!score.equals("")) score = score + " | ";
score = score + s_1 + ":" + s_2;
}
if (wincount > 0) {
win_tid = (String) t1.get("team_id");
} else {
win_tid = (String) t2.get("team_id");
}
String win = teams.getWinnerById(win_tid, p);
results.add(new Result(time, win, score));
}
return results;
}
//将获取的数据提取为Team对象
public static Team parseTeam(JSONObject obj) {
Team t;
String tid = (String) obj.get("uuid");
JSONArray players = (JSONArray) obj.get("players");
t = new Team(tid);
for (int i = 0; i < players.size(); i++) {
String tt = (String) players.get(i);
t.add(tt);
}
return t;
}
}
Team,Player]根据id编号进行排序,在后面比对的时候不用顺序遍历比较,而采用二分查找算法进行优化,加快比对获取结果的速度。//更改前
public String getNameById(String uid) {
for (int i = 0; i < this.len(); i++) {
if (players.get(i).getUuid().equals(uid)) {
return players.get(i).getFullname();//获取全名
}
}
return "信息比对出错";
}
//更改后【此处代码中省略了对compareTo接口的实现】
public String getNameById(String uid) {
int l = 0;
int r = this.len() - 1;
int m;
while(l <= r) {
m = (l + r) / 2;
if (players.get(m).getUuid().compareTo(uid) < 0) {
l = m + 1;
} else if (players.get(m).getUuid().compareTo(uid) == 0) {
return players.get(m).getFullname();
} else {
r = m - 1;
}
}
return "信息比对出错";
}
更改后速度有了略微的提升,这里用100次的叠加运行来观测。


StringBuilder类来处理字符串数据的串接。//更改前
public String getAll() {
String res = "";
if (this.len() != 0) {
for (int i = 0; i < this.len(); i++) {
if (i != 0) {
res = res + "\n";
}
res = res + this.get(i) + "\n" + "-----";
}
}
return res;
}
//更改后
public String getAll() {
StringBuilder res = new StringBuilder();
if (this.len() != 0) {
for (int i = 0; i < this.len(); i++) {
if (i != 0) {
res.append("\n");
}
res.append(this.get(i)).append("\n").append("-----");
}
}
return res.toString();
}
更改后速度有了很大的提升。


导入
junit4进行单元测试 对AOSearchTest作为AOSearch类的测试类进行单元测试

查看了代码情况后,未覆盖的主要都是异常捕获处理部分的代码。
输入部分判定:判断是否为两个参数,如果不是则输入错误信息结束。

IO异常:涉及文件IO的部分会有try-catch包裹,若文件不存在,则throw该异常,catch后输出相关错误信息。
程序中的查找比对错误,没有查到结果将会返回错误信息字符串,但由于不会影响输出和破坏结构因此我将其放入了结果的字符串中

本来学完java我就把eclips卸载了,因为这个作业,有幸马上有熟悉了一遍java的环境配置并尝试了新的写代码的软件——IDEA,才发现这个软件真的还挺好用的,当然为了使用也熟悉了一遍这个软件。其次,以前都不怎么用Gitcode这类的网站托管代码,因为作业,也熟悉了一遍相关的操作。再看到内容上,此次作业不仅让我熟悉了jar包的导入和调用,也了解了单元测试是如何进行的以及具体的一些操作细节。PSP表也是第一次见,感觉对于项目的规划还是非常有用也非常有帮助。总而言之,不管结果如何,学到的东西还是挺多的,也尝试了很多以前没尝试过的东西。
博客排版清楚,各部分完成的不错,继续加油