软件工程第二次作业

本文详细描述了一个关于世界游泳锦标赛跳水数据的控制台程序作业,涉及Gitcode项目管理、PSP阶段估算、JSON数据解析、fastjson和Junit的使用、接口封装、性能优化、单元测试以及异常处理。作者分享了解题思路和关键代码片段,强调了学习新工具和技术的重要性。
摘要由CSDN通过智能技术生成
这个作业属于哪个课程<班级的链接>
这个作业要求在哪里<作业要求的链接>
这个作业的目标实现一个能够对赛事数据进行统计的控制台程序

作业任务概述:

完成对世界游泳锦标赛跳水项目相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序。

一、Gitcode项目地址

gitcode项目地址链接: 项目地址

二、PSP表格

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

三、解题思路描述和接口封装

因为Java和C#都是完全面向对象的语言所以选择Java开发,使用IDEA开发。首先先解决JSON文件的读取和解析,通过csdn找到fastjson的jar包,并学习这个类库的使用方法。然后导入json的jar包,在进行单元测试时学习Junit方法,并导入Junit4.12的jar包。
然后针对问题设计对应的类,并在类中设计对应的解决方法。我个人的习惯是先大概确定整体的解决思路,然后直接开始上手写代码,在编码的过程中对自己思路的实现会遇到问题,每遇到一个问题就解决一个,直到最终完成。
具体的编码思路:构造设计Search类,包含几个关键的方法:Select()方法用于读取输入并判断指令;PlayersSearch()方法用于解决问题1;SportsSearch()方法用于解决问题二。期间使用了fastjson包用于解析JSON数据据,

问题1

问题1需要输出所有运动员的部分信息。调用PlayersSearch()方法,读取athletes.json文件,并分别提取国家,全名和性别数据,输出到指定的目标文件。athletes.json文件部分如下:
athletes数据
在读取中仅读取需要的信息:“CountryName”、“Gender”、“PreferredLastName"和"PreferredFirstName”。

问题2

问题2需要输出指定运动的比赛得分信息。调用SportsSearch()方法,先根据输入的项目名在event.json中找到项目对应的编号,再通过编号查找results中定义的项目文件。在项目文件中解析对应的成绩并输出到目标文件。
项目文件的结构如图(关键的结构信息在图片中标记出):
运动项目数据

四、关键代码展示

4.1DWASearch主类

主要为代码的启动器

public class DWASearch {
    public static void main(String[] args) {
         {
            Search search = new Search();
            List<String>commands =search.readinput("F:\\文档\\软件工程实践\\作业二\\project-java\\222100425\\src\\input");
            search.Select(commands,"F:\\文档\\软件工程实践\\作业二\\project-java\\222100425\\src\\output");
    }
    }

}

4.2Search类

4.2.1查找数据类,包含用于判断指令是否合法的exixts方法和对指令进行判对错和控制总控方法Select方法:

//指令判断
boolean exixts(String com){
        boolean tag = false;
        String[] array = {"result men 1m springboard", "result men 3m springboard", "result men 3m synchronised",
                "result men 10m platform", "result men 10m synchronised", "result women 1m springboard",
                "result women 3m springboard", "result women 3m synchronised", "result women 10m platform",
                "result women 10m synchronised", "result men 1m springboard detail", "result men 3m springboard detail",
                "result men 3m synchronised detail", "result men 10m platform detail", "result men 10m synchronised detail",
                "result women 1m springboard detail", "result women 3m springboard detail", "result women 3m synchronised detail",
                "result women 10m synchronised detail", "result women 10m platform detail"};
        for (int i = 0;i < array.length;i++){
            if (com.equals(array[i])){
                tag = true;
                break;
            }
        }
        return tag;
    }
    
  //总控方法
 public void Select(List<String> cmd,String filename){
        try {
            File file = new File(filename);
            if (!file.exists()) file.createNewFile();
            FileWriter filewriter = new FileWriter(file);
            filewriter.write("");
            filewriter.flush();
            filewriter.close();
        }catch (IOException e) {
            e.printStackTrace();
        }
        for (String command : cmd){
            //输出运动员信息
            if (command.equals("players")) PlayersSearch(filename);
                //输出运动项目结果
            else if(exixts(command)&&command.contains(" detail")==false){
                SportsSearch(command,filename);
            }
            else if(!exixts(command)) {
                if(command.contains("result ")==false&&command.contains(" detail")==false){
                    try {
                        FileOutputStream fos = new FileOutputStream(filename,true);
                        fos.write(("Error"+"\r\n").getBytes());
                        fos.write(("-----"+"\r\n").getBytes());
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("错误");
                    }
                }
                else {
                    try {
                        FileOutputStream fos = new FileOutputStream(filename,true);
                        fos.write(("N/A"+"\r\n").getBytes());
                        fos.write(("-----"+"\r\n").getBytes());
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("错误");
                    }
                }
            }
        }
    }

4.2.2两个针对问题1和2的解决方法调用PlayersSearch方法输出运动员信息,调用SportsSearch方法输出对应项目的比赛信息。代码如下

    public void PlayersSearch(String filename){
        try {
            FileOutputStream fos = new FileOutputStream(filename, true);
            JSONArray jsonarray = JSONArray.parseArray(ReadJsonFile("data/athletes.json"));
            for (int i = 0;i < jsonarray.size();i++){
                JSONObject jbt = jsonarray.getJSONObject(i);
                String countryname = jbt.getString("CountryName");
                JSONArray participations = jbt.getJSONArray("Participations");
                for (int j = 0;j < participations.size(); j++){
                    JSONObject pjbt = participations.getJSONObject(j);
                    String fullname = pjbt.getString("PreferredLastName") + " " + pjbt.getString("PreferredFirstName");
                    String gender = (pjbt.getInteger("Gender") == 0 ? "Male" : "Female");
                    fos.write(("FullName:"+fullname+"\r\n").getBytes());
                    fos.write(("Gender:" + gender+"\r\n").getBytes());
                    fos.write(("Country:" + countryname+"\r\n").getBytes());
                    fos.write(("-----"+"\r\n").getBytes());
                }
            }
            fos.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public void SportsSearch(String cmd, String filename){
        try {
            //将cmd中的result去除
            String[] parts = cmd.split(" ", 2);
            String sportsname = parts[1];
            FileOutputStream fos = new FileOutputStream(filename,true);
            JSONObject jbt = JSONObject.parseObject(ReadJsonFile("data/event.json"));
            JSONArray sportarray = jbt.getJSONArray("Sports");
            JSONObject sjbt = sportarray.getJSONObject(0);
            JSONArray disciplinelist = sjbt.getJSONArray("DisciplineList");
            for (int i = 0;i < disciplinelist.size();i++) {
                JSONObject dlist = disciplinelist.getJSONObject(i);
                if(sportsname.equalsIgnoreCase(dlist.getString("DisciplineName"))){
                    String id = dlist.getString("Id")+".json";
                    JSONObject jsonobject=JSONObject.parseObject(ReadJsonFile("data/results/"+id));
                    JSONArray heats=jsonobject.getJSONArray("Heats");
                    JSONObject jsonObject1=heats.getJSONObject(0);
                    JSONArray results=jsonObject1.getJSONArray("Results");
                    for (int j = 0; j < results.size(); j++) {
                        JSONObject selfresult=results.getJSONObject(j);
                        String fullname=selfresult.getString("FullName");
                        //双人赛数据
                        List<String> doublename=new ArrayList<>();
                        String Doublename="";
                        String rank=selfresult.getString("Rank");
                        String totalpoints=selfresult.getString("TotalPoints");
                        String detailscore="";
                        if(selfresult.containsKey("Competitors")&&selfresult.get("Competitors")!=null){
                            JSONArray competitors=selfresult.getJSONArray("Competitors");
                            for (int n = 0; n < competitors.size(); n++) {
                                JSONObject eachcompetitor=competitors.getJSONObject(n);
                                String eachname=eachcompetitor.getString("LastName")+" "+eachcompetitor.getString("FirstName");
                                doublename.add(eachname);
                            }
                            Collections.sort(doublename);
                            Doublename="'"+ doublename.get(0)+" & "+doublename.get(1)+"'";
                        }
                        JSONArray dives=selfresult.getJSONArray("Dives");
                        for (int k = 0; k < dives.size(); k++) {
                            JSONObject eachscore=dives.getJSONObject(k);
                            String EachScore=eachscore.getString("DivePoints");
                            if(k!=dives.size()-1) detailscore=detailscore+EachScore+"+";
                            else detailscore=detailscore+EachScore;
                        }

                        if(selfresult.containsKey("Competitors")&&selfresult.get("Competitors")!=null){
                            fos.write(("FullName:"+Doublename+"\r\n").getBytes());
                            fos.write(("Rank:"+rank+"\r\n").getBytes());
                            fos.write(("Score:"+detailscore+"="+totalpoints+"\r\n").getBytes());
                            fos.write(("-----"+"\r\n").getBytes());
                        }

                        else {
                            fos.write(("FullName:"+fullname+"\r\n").getBytes());
                            fos.write(("Rank:"+rank+"\r\n").getBytes());
                            fos.write(("Score:"+detailscore+"="+totalpoints+"\r\n").getBytes());
                            fos.write(("-----"+"\r\n").getBytes());
                        }
                    }
                    break;
                }
            }
            fos.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

五、性能改进

5.1:一开始对从input.txt文件中读取的指令是一行一行读取然后进行判断执行,这样子执行效率非常低,后面和同学交流后发现可以用List列表来统一读取指令,然后用循环的方法遍历List列表来对指令进行一一执行。修改后的代码如下:

    public List<String> readinput(String filename) {
        File file = new File(filename);
        List<String> ids = new ArrayList<>();
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
            ids = bufferedReader.lines().collect(Collectors.toList());
            return ids;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

5.2:最开始跑Junit覆盖率测试的时候发现覆盖率很不理想,后面有细看了Search类中的代码,发现有很多代码是冗余的,比如说因为Select总控制器的思想是在开发到后期时才想起来的,所以在SportsSearch方法中对是否在event.json文件中找到对应项目的id的判断是多余的,因为在Select中便对指令中项目是否存在就已经判断,所以可以直接删除SportsSearch方法中的判断,减少代码的冗余度。

六、单元测试

代码中的绝对路径为测试用。
使用Junit4对代码进行单元测试。测试的部分单元代码如下图所示:
单元测试代码
通过SearchTest类里的单元方法,对select、PlayersSearch和SportSearch这三个方法进行单元测试,每个测试的数据都不同,测试用例的编写主要注重正确的用例于不正确的用例并重,尽量确保用例的覆盖到所有的情况。10次测试均通过,下面是第一个测试的覆盖率:
覆盖率测试
覆盖率的提高方法我了解到的是:找到Search类中冗余的代码视情况删除或者看能否将他们合并。我找了一些在Search类中不常用的代码,有的将其删除了,有的进行优化(比如只有一句表达式的if语句,把if语句的括号删除)。提高了一点点覆盖率,不过提升很有限。

七、异常处理

除了对正常File文件或者数据流打开的异常处理外,还实现了对input.txt里的指令进行全方位的异常/错误情况的判断和输出。并且在Search类中的ReadJsonFile()方法中(该方法用于打开Json文件并将其转化为字符串),添加了Json文件找不到的异常情况处理。

八、心得体会

通过这次第二次作业,我对gitcode和Java语言中的json数据处理和Junit单元测试和代码覆盖率有了一定的理解。发现自己对开发语言的学习还有很多没有涉及到的知识,比如说对于不同数据结构文件的读取,测试调试的方法等等,自己需要在平常生活中扩展自己的代码能力和知识面。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值