这段代码如何打破德米特定律?

时间:2010-04-09 16:43:18

标签: java oop law-of-demeter

以下代码打破了Law of Demeter

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?

5 个答案:

答案 0 :(得分:3)

我认为这是两个问题:

  1. Grades逻辑与Student混合得太多了。它应该在Grades class
  2. 中完成
  3. Teacher的逻辑被放入Student
  4. 结论:学生对教师和成绩的内部结构和逻辑了解太多,并且会破坏LoD

答案 1 :(得分: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...
}

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

违反德米特定律的类Student中的方法

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

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

假设您希望继续隐藏成绩中学生和教师的成绩,解决此问题的一种方法是在类学生中定义代理方法(也称为委托方法),对内部成绩和教师进行操作代表应用程序的对象,类似于方法Student.isTeacher(int, String)。这个解决方案可能导致学生成绩和教师方法的重复,这是一个尊重LofD的disadvantage课程设计。

更好的解决方案是从学生中删除成绩和教师,并将他们全部放在另一个班级,比如成绩单:

class Transcript {
  Student student;
  Teacher teacher;
  Grades grades;
  Integer year;
}  

答案 4 :(得分:0)

让这两个私有函数破坏了LoD。

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

学生不需要逻辑来执行此类任务。

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

老师也一样。然后我会创建一个存储成绩信息的地方和另一个主题信息的地方。

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

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

主题也是数据对象。