OOP学习的第三次博客作业

发布时间 2023-06-25 14:28:30作者: 邓文迪

1)前言:

10-16周的几个礼拜内,我们主要是对菜单系统、成绩统计系统的迭代,在这过程中还有些许关于正则表达式以及setmap的相关联系,并且在这这六周期间,我们还进行了期中考试以及最后的课堂测验。在平时的练习中我意识到了面对较大工程的题目的时候,我的编程能力还是非常薄弱,不知道具体从哪一块开始入手,以及不知道怎么才能将各个个体、各个类串联起来,让他们成为一个有机的整体来去实现所要求的功能。面对系统题型的编程,主要的还是需要我们去掌握类之间的关系以及类内方法的相互调用。期中考试以及随堂测验中只要考察的也是对我们类之间关系的合理把控,以及collections.sort对类进行排序或者调用接口comparable进行排序,以及String函数和正则表达式。不论是平时测验还是平时作业,在题量和难度上对于我来说都是有点大和有点难的。但是在一次次完成作业,一次次完成测验中我不断的锻炼,编码能力也在不断提升。

(2)设计与分析:

面对7-1的课程成绩统计程序-1,显示总体浏览了一下题目,了解到了该题所需要我们完成的大概功能。最后完成的类图如下所示:

 

例如添加成绩功能以及添加课程信息功能,如下所示:

 /**
     * 添加课程信息
     */
    private static void addCourse(String courseName, String courseType, String accessMode) {
        if (courses.containsKey(courseName)) {
            // 已经存在该课程,忽略本次输入
            // return;
        }else {
            boolean isExam = "考试".equals(accessMode);
            boolean isRequired = "必修".equals(courseType);
            if (isRequired && !isExam) {
                System.out.println(courseName + " : course type & access mode mismatch");
            }
            Course course = new Course(courseName, isRequired, isExam);
            courses.put(courseName, course);
        }
    }

    /**
     * 添加成绩信息
     */
    private static void addGrade(String studentID, String studentName, String courseName, int dailyGrade, int finalGrade) {
//        if (!courses.containsKey(courseName))
        int flag1 = 0;
        for(int i = 0; i < courses.get(courseName).getGrades().size(); i++) {
            if (courses.get(courseName).getGrades().get(i).getStudentID().equals(studentID)){
                flag1 = 1;
                break;
            }
        }
        if(flag1 == 0) {
            if ((!courses.get(courseName).isExam() && courses.get(courseName).isRequired())) {
                // 课程不存在,输出错误信息
                System.out.println(courseName + " does not exist");
            }

            Course course = courses.get(courseName);
            if ((dailyGrade == -1) == course.isExam()) {
                // 成绩数量和考核方式不匹配,输出错误信息
                System.out.println(studentID + " " + studentName + " : access mode mismatch");
                //            return;
                finalGrade = -1;
            }
            if (!course.isExam() && course.isRequired()) {

                finalGrade = -1;
            }
            if (finalGrade > 100 || dailyGrade > 100) {
                dailyGrade = -1;
                finalGrade = -2;
                System.out.println("wrong format");
            } else {
                Grade grade = new Grade(studentID, studentName, courseName, dailyGrade, finalGrade);
                grades.add(grade);
                courses.get(courseName).addGrade(grade);
            }
        }

    }

 

在这里如果添加成绩的格式不对时我会将成绩命定为-1,方便与后面区别于正常成绩,可以让我们分辨出然后正常的输出。后面只要需要进行思考编程的便是成绩的输出,成绩的输出较为繁琐,脑筋需要从各个类中绕来绕去,花费了较多时间,以下拿课程平均分的计算来举例:

    /**
     * 输出班级所有课程总成绩平均分
     */
    private static void outputClassGradeAverage() {
        Map<String, List<Grade>> classGrades = new HashMap<>();
        for (Grade grade : grades) {
            String studentID = grade.getStudentID();
            String classID = studentID.substring(0, 6);
            if (!classGrades.containsKey(classID)) {
                classGrades.put(classID, new ArrayList<>());
            }
            classGrades.get(classID).add(grade);
        }
        List<String> classIDs = new ArrayList<>(classGrades.keySet());
        // 按班级号从小到大排序
        Collections.sort(classIDs);
        for (String classID : classIDs) {
            List<Grade> classGradeList = classGrades.get(classID);
            double totalGradeSum = 0;
            int totalGradeCount = 0;
            for (Grade grade : classGradeList) {
                double totalGrade = grade.getTotalGrade();
                if (!Double.isNaN(totalGrade)) {
                    totalGradeSum += totalGrade;
                    totalGradeCount++;
                }
            }
            if (totalGradeSum == -1) {
                System.out.println(classID + " has no grades yet");
            } else {
                double totalAverageGrade = totalGradeSum / totalGradeCount;
                System.out.println(classID + " " + (int) totalAverageGrade);
            }
        }
    }
}

在这里我用map定义了一个classgrades来统计课程成绩,用hashmap定义也方便按照班级号从小到大进行后续的排序,用map来定义也是方便后续用key值,也就是便于用班级号进行排序。由于collcetions.sort只能对list类型进行排序,所以我们先命定一个list数组来储存班级号的信息,方便于我们进行排序之后,再根据起初定义的map类型的classgrades中获取成绩信息来输出课程成绩信息。因为前面我们对添加成绩的时候,如果成绩的输入格式不对或者错误的话,对成绩的定义为-1,所以这里我们输出的时候也进行相关的判断,如果是-1的话就进行相应的错误信息输出。

之后的课程成绩统计程序-2,再课程成绩统计程序-1的基础上增加了实验课,所以面对课程以及课程成绩的输入输出都要进行相应的修改,并且定义的课程类也要进行修改。修改之后的类图如下所示:

 因为实验成绩的输入和其他课程的输入截然不同,于是我在这里另创建了一个方法来添加实验成绩。如下所示:

    private static void addExperimentGrade(String studentID, String studentName, String courseName,  int experimentTimes , List<Integer> experimentGrades) {
        if (!courses.containsKey(courseName) || courses.get(courseName).isExam()) {
            // 课程不存在或者为考试课程,输出错误信息
            System.out.println(courseName + " does not exist");

        }
        int flag = 0;
        Course course = courses.get(courseName);
//        if (experimentGrades.length != course.getExperimentTimes()) {
//            // 实验次数和要求不符,输出错误信息
//            System.out.println(studentID + " " + studentName + " : experiment times mismatch");
//
//        }

        for (int experimentGrade : experimentGrades) {
            if(experimentGrade == -1)
                System.out.println(studentID + " " + studentName + " : access mode mismatch");
            if(experimentGrade >100 ) {
                System.out.println("wrong format");
                flag = 1;
            }
        }
//        if(experimentTimes !=experimentGrades.size()){
//            System.out.println(courseName + " : course type & access mode mismatch");
//        }
        if(flag == 0) {
            Grade grade = new Grade(studentID, studentName, courseName, experimentTimes, experimentGrades);
            grades.add(grade);
            course.addGrade(grade);
        }
    }

在此基础上也进行了course类、grade类中就实验课进行了修改,在course类中我创建了专门计算实验课成绩平均值的方法,因为实验课成绩的计算与其他课程不同。代码如下所示

public double getExperimentAverage() {
        if (grades.isEmpty()) {
            return -1;
        }
        int times = 0;
        int experimentGradeSum = 0;
        for (Grade grade : grades) {
            List<Integer> experimentGrades = grade.getExperimentGrades();
            for (int experimentGrade : experimentGrades) {
                experimentGradeSum += experimentGrade;
            }
            times += grade.getExperimentTimes();
        }
        return (double) experimentGradeSum / (times);
    }
    public List<Grade> getGrades(){
        return grades;
    }
}

 通过这两次题目统计系统的编写,我对大型代码的编写,对于各个类之间根据关系的创建以及方法的引用具有更好的掌握。在一次次迭代的过程中也不断增强了自身的编码能力。

而面对oop9中 统计Java程序中关键词的出现次数,与上述题目一样,锻炼到了我们使用set和map的能力。

for (Map.Entry<String, Integer> entry : counter.entrySet()) {
            System.out.println(entry.getValue() + "\t" + entry.getKey());
        }

这里进行对map的遍历,值得我铭记。

(3)踩坑心得:

  在我们编写较长代码,其中含有很多类很多方法的时候,我们会不知道如何使用相应的方法实现功能,因为再java中不再使用全局变量,所以很容易调用过来的是空的,这让我们经常出现错误。我们需要清楚的了解自己想要调用的东西是属于哪一个类中,定义该事物的时候是属于哪一个类中,这会方便我们将数据统合在一起,不会出错。由于之前没有接触过set、map两类类似于数组的定义,所以在这些周的编码过程中会有些许困难,需要查阅大量的资料去了解两类方法的使用,map中的key、value值及其相关方法也耗费了大量使用是搞明白。之后的几次联系以及平时测验也都是围绕set、map以及各个类之间关系的构建而去编写的题目,我们只要在编写代码之前搞清楚了各个类之间的关系,不要囫囵吞枣,还没搞清楚之间的关系就开始下手敲代码,这会导致我们编写到途中发现自己的编写的程序前言不搭后语。所以每次我们动手前都需要想清楚各个类中需要编写什么方法,定义什么属性,以及各个类之间是什么关系,有什么关联,有什么方法是大家公共都会用到的。之后的联系还主要涉及到的是collections.sort的排序,其中包括使用comparable或者comparator进行排序,如果使用comparable进行排序就用使用方法compareTo进行排序方法的定义,如果是后者就是使用compare,各有千秋,两者具有共同之处,只要掌握了排序前后的道理就可以了。刚开始接触这类排序的时候,时常搞不清楚前后两项的关系,返回值的正负所带来的排序顺序是怎么样的,导致时常排序顺序弄反,我们在自己编程中多多进行试错,就会发现其中道理。

(4)改进建议:

  两个成绩管理系统以及统计Java程序中关键词的出现次数题目中我并没有拿到满分,也许自己所编写的代码量还是太少了,编程能力还不够,即使花费了时间后也无法成功通过各个测试点。并且在面对例如成绩管理系统这种需要较长时间去编写大量代码的题目中,我时常静不下心来去好好思考其中的奥秘,导致每次我花费较长时间也毫无收获,也是我经历少、能力不够的一种表现吧。并且在我最后编写完完整程序之后,发现我的程序有些地方并没有用最简洁的编程语言去表达实现功能。希望以后可以逐步提升自己的能力,用更加精简且让读者易于理解的编程语言去完成编程。重要的在一个学期的过程中,更改自己的编写格式是很重要的,我从起初的胡乱变成到现在可以基本按照大企那样规定的格式编程,但我仍然没有做到该注释的地方加以注释,希望以后我能改进这个地方。

(5)总结:

  在前三次作业中我学习到了java的基本编程语言的不同之处,掌握了基本的java程序设计(输入、输出、部分基本方法等等),学习到了类的定义以及类中方法的定义与引用 ,让我对java编程的框架有了大致的掌握。但是类的编写已经引用一些不熟悉的方法让我们感觉到java编程非常有难度。我觉得java课上讲的东西都非常的深奥,感觉对我目前的编程相关性不大。平时的pta作业也非常有难度,经常要写很久都写不出来。非常的具有难度,感觉都是新知识,都没有学习,都得自己看网上的,这非常考验自己的自学能力,得查阅非常多的资料才能了解编程该程序到底需要什么,目前的作业和实验对于我们个人的能力的考验非常大,难度以及挑战性也是较大的。再之后的三次作业,学习到了如果运用Array.sort直接对需要排序的字符串乃至数组进行直接排序,无需我们进行繁琐的for循环。直接开始接触到了Scanner类中nextLine()等方法、String类中split()等方法、Integer类中parseInt()等方法的用法,了解LocalDate类中of()、isAfter()、isBefore()、until()等方法的使用规则,了解ChronoUnit类中DAYS、WEEKS、MONTHS等单位的用法。通过此次作业中了解到了各种类中的方法以及温习了类与构造方法的构建。让我领略到了java文档库中有许多实用的方法供我们使用,我们以后无需进行复杂的编码去实现部分功能的实现,我们可以直接调用库中的方法进行运算。通过第二次的作业我也学习到了正则表达式的基础使用,但是里面的知识我们之前从来没有接触过,表达方式也是从未见过,字符也是过于新鲜。现在只是接触,要想掌握还需再课后完成任务之后花更多的时间去理解与记忆。在一次次的学习中我们具有了更强的逻辑思维能力,懂得在运行大规模程序的过程中要如何一步步的进行操作。正如现在我懂得了在遇到复杂程序的时候,第一步是要进行大致框架的构建,在老师的引导下,以及我自己多次编写程序的过程中,对powerdesigner的使用更加的精湛,并且懂得了在编写完代码后直接一键生成类图以及在构建完类图后powerdesigner可以帮助我们构建出代码的大体框架。画出正确的类图可以帮助我们更快的编写出代码的大体框架的同时,具有良好的思维逻辑。最后几次作业和课堂测验主要是加深我们对各个类之间关系的掌握以及方法的引用以及对map、set方法的使用并且对collections.sort方法的使用。在长达一个学期的java学习中,我基本了解到了什么是面向对象编程,更多的需求不再是为了去完成需求去编码,更多的面向对象,这样让我的代码更加灵活,利于我们变通迭代。不过我的学习之路还很长,需要学习的东西还很多,现在能力还是一般,希望在以后学习生涯中不断提升自己的编程能力,让自己更加全面,更加有能力去完成更难的难题。

(7)客观评价与建议:

  本课程开设的教学理念我认为是让我们面向对象编程,而不再是面向结果、面向题目编程,让我们成为一个随机应变的人,懂得更多的编程模式,更灵活变通,实行的非常好。教学方法起初由于我们的基础薄弱,主要的还是让我们学习,在之后我们的基础夯实之后,更多的是让我们在课堂上自己动手练习,非常好,但是有时候问题过于深奥,难度过于大,老师不加以点播,我们往往无法在课堂上完成。教学组织还是比较好的,学习通上有相应的网课教学,如果我们课上没听懂可以去学习同上观看,但是老师每次都打开关闭教程无声,我们无法及时捕捉老师的意图,每次还没看完老师就关闭了课程观看权限,或者我想要复习的时候,也是没有权限去观看。pta上布置作业,我认为作业量过大,作业难度过大,我们有时候即使花费大量时间也无法完成,并且有些联系并不是跟随着课堂布置的,自我认为与课堂讲述的相关性不大。教学模式有时候采用翻转课堂,学生做教学的主导者,上台演讲,这不仅让我们学习到了做老师,也让我们学习到了知识,我认为还不错,但是有时候同学们讲述的非常快,导致坐下面的同学不是很能理解,我认为这个时候老师就要主动站出来加以补充,这样才可以真正做到教学的目的。