688
社区成员
发帖
与我相关
我的任务
分享软件工程实践第二次作业——个人实战
| 这个作业属于哪个课程 | 2023年福大软件工程实践课程W班 |
|---|---|
| 这个作业要求在哪里 | 软件工程实践第二次作业 |
| 这个作业的目标 | 代码编写、撰写单元测试、撰写博客 |
| 其他参考文献 | 单元测试与回归测试-邹欣 |
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) | ||
|---|---|---|---|---|---|
| Planning | 计划 | 610 | 875 | ||
| • Estimate | • 估计这个任务需要多少时间 | 610 | 875 | ||
| Development | 开发 | 590 | 860 | ||
| • Analysis | • 需求分析 (包括学习新技术) | 30 | 20 | ||
| • Design Spec | • 生成设计文档 | 60 | 15 | ||
| • Design Review | • 设计复审 | 10 | 5 | ||
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 60 | 120 | ||
| • Design | • 具体设计 | 30 | 10 | ||
| • Coding | • 具体编码 | 360 | 400 | ||
| • Code Review | • 代码复审 | 10 | 20 | ||
| • Test | • 测试(自我测试,修改代码,提交修改) | 30 | 270 | ||
| Reporting | 报告 | 20 | 15 | ||
| • Test Report | • 测试报告 | 10 | 5 | ||
| • Size Measurement | • 计算工作量 | 5 | 5 | ||
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 5 | 5 | ||
| 合计 | 610 | 875 | |||
在已有json数据的情况下,项目主体需要三个主要部分:
1.解析json数据的解析类,作为工具解析所需要的Json数据,参数为Json文件名
2.两个功能各一个类,作为分开的两个功能,调用Json解析类获取根对象,并进行解析。
3.测试类,每写一个功能就可以对其方法进行测试。
并且,由于实现过程需要用到json解析,则需要寻找相应的解析包,项目最终使用阿里巴巴的fastJson,性能较好。单元测试也需要引入Junit,项目使用Junit4
首先数据解析类作为工具,可设计为一个静态的工具方法。两个功能类结构应该大体类似,可设计一个抽象类,便于维护两个类的方法和数据;功能内动态使用来自文件的指令,故没有创建文件路径的常量类;没有将数据和逻辑分离。

解析类使用fastJson来实现具体的解析,传入参数为文件路径,主要方法为JSONObject.parseObject(String text),使用它将json数据字符串解析为根对象并输出,所用文件使用Java的文件流InputStreamReader类读取json文件。
public static JSONObject readJsonObject(String fileName) {
String str="";
try {
int c;
InputStream inputStream=JsonParserUtil.class.getClassLoader().getResourceAsStream(fileName);
InputStreamReader reader=new InputStreamReader(inputStream, StandardCharsets.UTF_8);
StringBuilder stringBuilder=new StringBuilder();
while((c= reader.read())!=-1) {
stringBuilder.append((char)c);
}
str= stringBuilder.toString();
reader.close();
}
catch (IOException e) {
e.printStackTrace();
return null;
}
return JSONObject.parseObject(str);
}
1、主要方法的参数为指令及所输出的目标文件,将输出部分按要求分为四个方法:验证和获取时间、获胜者、分数。验证使用正则表达式验证,并返回对应验证结果。原数据中获取分数时由于数据嵌套复杂,需要一层一层循环读取,新数据只有一层嵌套,可直接获取数组或对象再获得属性。获胜者即获取到队伍id后到teams中找到players数组,再到players中寻找。
private void CreateWinner(StringBuilder builder, String teamId) {
JSONArray winners = null;
// 获得player的uuid
for (int m = 0; m < allTeams.size(); m++) {
String uuid = (String) JSONPath.eval(allTeams, "$[" + m + "].uuid");
if (uuid.equals(teamId)) {
winners = (JSONArray) JSONPath.eval(allTeams, "$[" + m + "].players");
break;
}
}
builder.append("winner:");
if (winners.size() == 1) {
builder.append(uuid2Name.get(winners.getString(0)));
} else {
builder.append(uuid2Name.get(winners.getString(0)));
for (int m = 1; m < winners.size(); m++) {
String winner = winners.getString(m);
builder.append(" & ").append(uuid2Name.get(winner));
}
}
builder.append("\n");
}
private void CreateScores(StringBuilder builder, JSONObject teamA, JSONObject teamB) {
JSONArray scoresA = teamA.getJSONArray("score");
JSONArray scoresB = teamB.getJSONArray("score");
builder.append("score:");
String first = JSONPath.eval(scoresA, "$[0].game") + ":"
+ JSONPath.eval(scoresB, "$[0].game");
builder.append(first);
for (int m = 1; m < scoresA.size(); m++) {
String once = JSONPath.eval(scoresA, "$[" + m + "].game") + ":"
+ JSONPath.eval(scoresB, "$[" + m + "].game");
builder.append(" | ").append(once);
}
builder.append("\n-----\n");
}
2、选手信息嵌套简单,只需要直接读取对应的数据即可。
private String CreateOutput() {
StringBuilder builder=new StringBuilder();
JSONArray players = playerJsonObject.getJSONArray("players");
for (int i = 0; i < players.size(); i++) {
JSONObject player = players.getJSONObject(i);
String name = player.getString("full_name");
String gender = player.getString("gender");
if (gender.equals("M")) {
gender = "male";
} else {
gender = "female";
}
String nationality = (String) JSONPath.eval(player, "$.nationality.name");
builder.append("full_name:").append(name).append("\n");
builder.append("gender:").append(gender).append("\n");
builder.append("nationality:").append(nationality).append("\n-----\n");
}
return builder.toString();
}
1.程序优化大概花费20min,主要在实现阶段完成。
2.此程序大部分优化可以通过在方法前进行空判断以跳过某次循环或不需要创建对象直接输出。
3.不同对象中的跳转查找可以进行结构优化封装,在解析类中实现类似数据库的联合查找。(未实现)
4.由于功能类只支持单条指令,故在循环使用功能时若有连续相同的指令可在内部缓存读取出的对象,避免反复解析。
输出过长故只显示部分输出
测试函数创建input.txt文件并创建上图的指令,类型包括前后空格、多分隔、错误指令、错误文件名等。输出后将数据从output.txt读取至控制台并删除文件。
private void InitInputText() {
File file = new File("input.txt");
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
FileWriter writer = null;
writer = new FileWriter(file, true);
writer.write("player\n");
writer.write("result.\n");
writer.write(" player\n");
writer.write("\n");
writer.write("result 1\n");
writer.write("result 01 16\n");
writer.write("players 1\n");
writer.write("result 01161\n");
writer.write("result 0116\n");
writer.write("result 0116\n");
writer.write("players\n");
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
工具类JsonParseUtil测试,主要测试是否找到文件。
@Test
public void Test() {
assertNull(JsonParserUtil.readJsonObject("6"));
JSONObject obj= JsonParserUtil.readJsonObject("src/data/players.json");
assert obj != null;
}

经判断部分的IOException(文件是否存在)没有测试到,即文件是否存在的问题。
计算部分的异常分为文件异常和指令的异常,文件名不存在或其他错误因方法固定需要而生成try-catch语句块,指令异常判断为null(非法指令),N/A(Json文件不存在)
此次项目完成时间上与预期相差很大,分析后原因有:1.旧数据的结构复杂,同时需要分析属性作用。2.没有单元测试经验,误判了单元测试的时间。3.以为Json数据结构简单。4.中途变更了数据 5.需求分析阶段时间不充分,导致花费大量时间创建了无用数据。
不过由于在其他项目中解析过Json数据,故时间可以整体缩减。对项目整体分析后,认为整体结构还可以更好,如减少一些嵌套等。
项目的解题思路可以写的再详细一点哈,继续加油!