1

这更像是一个设计问题,涉及代码简单性与性能。

假设您要确保给定用户 ID 的一组值在两个系统之间是相同的。此处的示例是检查一个学生 ID 在系统 A 和系统 B 中的课程注册数量是否相同。

为此,我们创建:

List<String> studentList = new ArrayList<String>();
Set<String> sysAEnrollments = new HashSet<String>();
Set<String> sysBEnrollments = new HashSet<String>();
private Map<String, String> badEnrollList = new HashMap<String, String>();

并适当地填写它们,给定一个学生 id 列表(studentList):

studentList = getCurrentStudentList();

for (String id : studentList){
   sysAEnrollments = getSysAEnrollments(id);
   sysBEnrollments = getSysBEnrollments(id);
   if (!sysAEnrollments.containsAll(sysBEnrollments)){
      badEnrollList.put(id, getBadEnrollmentsById(id, sysAEnrollments, sysBEnrollments));
   }
}

问题:方法“ getBadEnrollmentsById ”应该返回什么?

要么是具有足够含义的串联字符串,因此可以将其打印出来。或者有一个新对象,例如另一个包含课程 ID 列表的集合,可用于进一步处理但更难用于打印输出。

为了清晰和性能,是否值得彻底设计所有预期对象或用连接字符串替换其中一些?

笔记:

  • 系统A优先作为权威来源
  • getBadEnrollmentsById的输出应该包含所有课程并标记系统 B 中缺少的课程。

建议的解决方案:(2012-SEP-14)

编辑(2012-SEP-17):更新 Course 类以包括 hashCode 和 equals

根据 user351721 的建议,我继续对符合预期结果/要求的剩余对象进行建模。微小的改变产生了很大的不同,让我能够克服这个设计缺陷并完成实现。

修改后的集合是:

List<String> studentList = new ArrayList<String>();
Enrollment sysAEnrollments;
Enrollment sysBEnrollments;
Map<String, List<String>> badEnrollList = new HashMap<String, List<String>>();

我们填充注册:

for (String id : studentList){
    sysAEnrollments = getSysAEnrollments(id);
    sysBEnrollments = getSysBEnrollments(id);
    if (!sysAEnrollments.getCourses().containsAll(sysBEnrollments.getCourses())){
        List<String> missingCourses = getProblemEnrollmentListById(id, sysAEnrollments, sysBEnrollments);
        badEnrollList.put(id, missingCourses);
    }
}

因此,现在可以通过获取每个 ArrayList 并打印课程名称来从 badEnrollList 打印输出。带有 * 的课程名称意味着它在 sysB 中缺失。

Enrollment 类如下所示:

public class Enrollment {
    private Set<Course> courses = new HashSet<Course>();
    public void setCourses(Set<Course> courses){
        this.courses = courses;
    }
    public Set<Course> getCourses(){
        return this.courses;
    }
}

Course 课程最终是这样的:

public class Course {
    private String id;
    private String name;

    public String getId() {
        return id;
    }
    public void setId(final String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(final String name) {
        this.name = name;
    }

    // Must override hashCode() and equals()
    @Override
    public boolean equals(Object o){
        if (o == this)
            return true;
        if (!(o instanceof Course))
            return false;
        Course c = (Course) o;
        return c.id.equals(this.id) && c.name.equals(this.name);
    }

    @Override 
    public int hashCode(){
        // Magic numbers as shown on Joshua Bloch's book "Effective Java" 2nd Edition, p.48
        int result = 17;
        result = 31 * this.id.hashCode();
        result = 31 * this.name.hashCode();
        return result;
    }   
}

这些变化可能看起来很微妙,但重要的线索是 Enrollments 不是字符串的集合,Enrollments 是 Courses 的集合,并且每个 Course 都有一个名称和一个可用性属性。它们似乎没有做太多,但通过使用它们,我定义了我正在使用的对象,并记录了这些类在未来如何被重用。

4

4 回答 4

1

连接字符串

这意味着您必须定义一个模式和相应的一组有效字符串,并实现对实体类的验证和转换。提供一个接口或类将使您在一年左右的时间内更容易更新您的代码,更不用说可能与您的应用程序一起工作的其他程序员了。为什么不将学生、注册或课程对象存储在 中badEnrollList?这些对象看起来如何,您想用它们做什么?

一般来说:是的,彻底设计所有预期的对象是值得的。

于 2012-09-13T22:47:05.340 回答
1

我觉得一个集合,例如List<String>将是一个理想的返回值。这使您可以更有效地捕获两组之间的多个差异,并更直观地处理第二个对象中缺失的课程。打印列表也不会那么难 - 取决于您希望如何传达信息。

还值得一提的是,for 的.equals()方法Set是一种更简洁、更直观的方式来确保两组之间的等价性。

于 2012-09-13T23:10:53.350 回答
1

“Growing Object-Oriented Software, Guided by Tests”解决了这个问题:第 7 章,“值类型”。值得一读。摘录:

我们编写的代码越多,我们就越相信我们应该定义类型来表示域中的值概念,即使它们没有多大作用。它有助于创建一个更不言自明的一致域模型。例如,如果我们在系统中创建一个 Item 类型,而不仅仅是使用 String,我们可以找到与更改相关的所有代码,而无需跟踪方法调用

于 2012-09-14T01:46:16.493 回答
0

我不会使用所有这些集合和映射,而是使用反映实际业务对象的普通旧 Java 对象 (POJO)。根据您的指示,您的学生具有某种 id,并且在系统 A 和系统 B 上注册了课程。我将构建一组定义如下的学生对象:

public class Student {
    private String id;
    private List<String> enrollmentsA;
    private List<String> enrollmentsB;

    // appropriate getters and setters
}

根据您是否想对类做任何其他事情,甚至最好创建某种形式的 EnrolledClass 对象来表示它。

在学生班级中,我将有一种方法来确定“不良”入学率。如果您想要对这些数据做的只是生成一封电子邮件,它甚至可以像字符串一样简单:

public String getBadEnrollmentsMessage() {
    List<String> enrolledBoth = getCommonEnrollments();
    List<String> enrolledOnlyA = getAOnlyEnrollments();
    List<String> enrolledOnlyB = getBOnlyEnrollments();

    StringBuilder output;
    // format the contents of the above lists into output
    // format should be however you want it in the email.

    return output.toString();
}

然后,您可以将学生地图发送到电子邮件注册消息:

HashMap<Student, String> studentEmails;

for (Student s : allStudents) {
    studentEmails.put(s, s.getBadEnrollmentsMessage());
}

当然,如果您有类似的方法getBadEnrollmentsMessage(),我什至不确定您是否首先需要学生和字符串的 Map。坦率地说,您可以创建一个sendEnrollmentEmail方法,传入 a ,然后通过那里Student提取消息。getBadEnrollmentsMessage()

于 2012-09-14T01:23:14.540 回答