4

以下代码违反了得墨忒耳定律

public class Student extends Person {
  private Grades grades;

  public Student() {
  }

  /** Must never return null; throw an appropriately named exception, instead. */
  private synchronized Grades getGrades() throws GradesException {
    if( this.grades == null ) {
      this.grades = createGrades();
    }

    return this.grades;
  }

  /** Create a new instance of grades for this student. */
  protected Grades createGrades() throws GradesException {
    // Reads the grades from the database, if needed.
    //
    return new Grades();
  }

  /** Answers if this student was graded by a teacher with the given name. */
  public boolean isTeacher( int year, String name ) throws GradesException, TeacherException {
    // The method only knows about Teacher instances.
    //
    return getTeacher( year ).nameEquals( name );
  }

  private Grades getGradesForYear( int year ) throws GradesException {
    // The method only knows about Grades instances.
    //
    return getGrades().getForYear( year );
  }

  private Teacher getTeacher( int year ) throws GradesException, TeacherException {
    // This method knows about Grades and Teacher instances. A mistake?
    //
    return getGradesForYear( year ).getTeacher();
  }
}

public class Teacher extends Person {
  public Teacher() {
  }

  /**
   * This method will take into consideration first name,
   * last name, middle initial, case sensitivity, and
   * eventually it could answer true to wild cards and
   * regular expressions.
   */
  public boolean nameEquals( String name ) {
    return getName().equalsIgnoreCase( name );
  }

  /** Never returns null. */
  private synchronized String getName() {
    if( this.name == null ) {
      this.name == "";
    }

    return this.name;
  }
}

问题

  1. LoD是如何被破坏的?
  2. 破坏 LoD 的代码在哪里?
  3. 应该如何编写代码来维护 LoD?
4

5 回答 5

3

我认为这里有两个问题:

  1. Grades逻辑混杂太多Student。应该在Grades课堂上完成
  2. Teacher的逻辑放入Student.

结论:学生对教师和成绩的内部结构和逻辑了解太多,这打破了LoD

于 2010-04-09T16:51:08.943 回答
2

诸如此类的大多数问题都可以通过重新访问您的域模型来解决。

看起来学生比它应该承担的责任要多得多。它应该只有一个改变的理由。

我会通过添加一个 ReportCard 对象来重构它。

public class ReportCard
{
  public Student Student...
  public int Year...
  public ReportCardItem[] ReportCardItems...

  getGrades()...
  createGrades()...
}

public class ReportCardItem
{
  public Grade Grade...
  public string Subject...
  public Teacher Teacher...
}
于 2010-04-09T19:44:33.020 回答
1

学生课堂上违反得墨忒耳法则的方法是

private Grades getGradesForYear( int year )
private Teacher getTeacher( int year )

因为这些将域对象 Grades 和 Teacher 暴露给应用程序。

假设您希望继续将 Grades 隐藏在 Student 中,将 Teacher 隐藏在 Grades 中,解决此问题的一种方法是在 Student 类中定义代理方法(也称为委托方法),它们代表对内部 Grades 和 Teacher 对象进行操作的应用程序,类似于方法Student.isTeacher(int, String)。这种解决方案可能会导致方法在 Grades 和 Teacher in Student 中的重复,这是尊重 LofD 的班级设计的一个缺点

更好的解决方案是从 Student 中删除 Grades 和 Teacher 并将它们全部放在另一个班级中,例如 Transcript:

class Transcript {
  Student student;
  Teacher teacher;
  Grades grades;
  Integer year;
}  
于 2010-04-09T20:23:51.867 回答
1

Person.isTeacher根据您提到的维基百科文章“到达”。

我惊讶地发现成绩列表是学生的财产。这不应该是学校知道和管理的事情吗?我会问学校,哪位老师在哪一年给学生评分...

于 2010-04-09T16:50:30.187 回答
0

拥有这两个私有函数会破坏 LoD。

private Grades getGradesForYear( int year )
private Teacher getTeacher( int year )

学生不应该需要逻辑来执行这些任务。

我重新设计的方法是将数据与逻辑分开。学生应该纯粹是一个数据。它应仅包含有关学生和学生的信息。因此,这不包括成绩,因为该概念需要其他人,例如学科和老师。

老师也是一样。然后,我将创建一个存储成绩信息的位置和另一个存储主题信息的位置。

要执行类似的任务,我会这样做:

gradesDatabase.getGrade(subject, student);
subjectDatabase.getTeacher(subject, student);

主题也是仅数据对象。

于 2010-04-09T16:58:09.367 回答