readme

Java面向对象程序设计-查找优秀学生

需求分析

我们在之前的项目中创建了StudentCenter类,其中包含了学生注册课程的信息。在课程结束之后,教师常常会查看一下在该课程中表现最优秀的学生。我们将在本项目中实现查找最优秀学生的功能。

步骤一

我们首先在com.littlewaterdrop.bean包中新增一个类StudentCourseRecord,它表示学生在课程中的表现情况。它包含了四个私有成员变量:(1) studentId,字符串类型,用于表示学生id,即Student.id;(2) courseId,字符串类型,用于表示课程id,即Course.id;(3) grade,单精度浮点型,用于表示学生在该课程中获得的分数;(4) attendance,整数类型,用于表示学生上课出勤的次数。

StudentCourseRecord有一个构造函数,接收四个参数:studentId、courseId、grade和attendance,分别用于初始化上述四个成员变量。StudentCourseRecord类还提供了getter和setter方法,用于访问和更新上述四个成员变量。

类似的,我们在com.littlewaterdrop.factory包中创建一个新类StudentCourseRecordFactory,用于创建StudentCourseRecord对象。

public class StudentCourseRecordFactory {
    public static StudentCourseRecord newStudentCourseRecord(String studentId, String courseId, Float grade, Integer attendance) {
        ...
    }
}

步骤二

然后,在StudentCenter类中新增一个私有成员变量,类型为StudentCourseRecord的数组。该数组保存了所有学生的课程记录。

我们再创建一个新的成员方法,命名为findHighestGrade(),用于查找在所有的学生课程记录中,获得分数最高的学生的id。所以,该方法没有输入参数,它返回一个String类型的结果,表示学生id。其原型如下所示。

public class StudentCenter {
    public String findHighestGrade();
}

步骤三

教授可能还会查询某一门课程中得分最高的学生id。所以,我们在StudentCenter类中新增一个成员方法,命名为findHighestGradeInCourse()。该方法接收一个String类型的参数,用于表示课程id;返回一个String类型的参数,表示该课程中得分最高的学生id。如果课程或者学生不存在,则返回null。新方法的原型如下所示。

public class StudentCenter {
    public String findHighestGradeInCourse(String courseId);
}

步骤四

类似的查询还有许多。例如,教授可能会查询在某门课程中,当出勤次数(attendance)大于等于30次时,得分最高的学生id和出勤次数(attendance)小于20次时,得分最高的学生id。

所以,在步骤四中,我们将建立一个查询的流程,并使用策略模式,来满足上述各项的查询需求。实际上,我们是将上述的查询需求包装在各项策略之中。

首先,我们创建一个新的"资格"策略接口QualificationStrategy,放在com.littlewaterdrop.strategy包中。该接口声明了一个成员方法isQualify()。该方法接收一个StudentCourseRecord对象;返回一个boolean类型的结果,表示该StudentCourseRecord对象是否应该在查询中被考虑。在QualificationStrategy上使用标注@FunctionalInterface

public interface QualificationStrategy {
    boolean isQualify(StudentCourseRecord record);
}

其次,我们再创建一个新的比较接口RecordComparisonStrategy,放在com.littlewaterdrop.strategy包中。该接口声明了一个成员方法compare()。该方法用于比较两个StudentCourseRecord对象并返回一个int类型的结果。当对象a比b更"好"时,返回1。当对象b比a更"好"时,返回-1。当a和b同样优秀时,返回0。在RecordComparisonStrategy上使用标注@FunctionalInterface。

public interface RecordComparisonStrategy {
    int compare(StudentCourseRecord a, StudentCourseRecord b);
}

其时,在Java标准库中已提供了类似的接口。java.util.function.Predicate已提供了QualificationStrategy相似的功能。java.util.Comparator提供了RecordComparisonStrategy相似的功能。但是,本项目作为一个教学项目,还是希望学员能够自行定义并实现这两个接口。

最后,我们在StudentCenter类中创建一个新的方法findStudentByStrategy()。该方法接收两个参数;第一个参数为QualificationStrategy对象,用于过滤不合格的StudentCourseRecord对象。第二个参数为RecordComparisonStrategy对象,用于比较多个StudentCourseRecord对象之中需要返回的那个对象。

private String findStudentByStrategy(QualificationStrategy qualification, RecordComparisonStrategy comparator) {
    return Arrays.stream(records) // stream of StudentCourseRecord
            .filter(x->qualification.isQualify(x))  // stream of StudentCourseRecord
            .max((x,y)->comparator.compare(x,y))  // Optional<StudentCourseRecord>
            .map(StudentCourseRecord::getStudentId)  // Optional<String>
            .orElse(null)
            ;
}

步骤五

在步骤五中,我们将实现上述的查询方法。在实现findHighestGrade()方法时,所有的StudentCourseRecord对象都参与比较。因此,可以使用一个QualificationStrategy对象,在任何情况下都返回true。因为我们使用了标注@FunctionalInterface,我们可以这样创建QualificationStrategy对象。

QualificationStrategy alwaysQualifiedStrategy = (x) -> true;

然后,我们需要寻找分数最高的那位学生。因此,我们可以使用如下的策略,使用分数来比较哪个学生分数更高。在这里,我们可以直接使用Float对象的compare()方法。如果grade字段的类型是float的话,可以使用Float.valueOf()将其转换成Float对象,然后再比较。

RecordComparisonStrategy higherGradeBetterStrategy = (a, b) -> a.grade.compare(b.grade);

最后,我们可以使用上述的两个策略对象来实现findHighestGrade()方法。

public String findHighestGrade() {
    return findStudentByStrategy(alwaysQualifiedStrategy, higherGradeBetterStrategy);
}

类似的,当需要查询某一门课程得分最高的学生的时候,我们可以使用一个QualificationStrategy对象,过滤其他课程的记录。因此,我们可以这样实现findHighestGradeInCourse()方法。

public String findHighestGradeInCourse(String courseId) {
    QualificationStrategy courseFilter = (x) -> courseId.equals(x.getCourseId());
    return findStudentByStrategy(courseFilter, higherGradeBetterStrategy);
}

我们还可以在QualificationStrategy对象的实现中添加出勤次数的判断,以实现更加丰富的查询方法。

参考文档

  1. Java编程语言的基本概念
  2. 设计模式
  3. Maven工程管理工具
Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.