Как этот код нарушает закон Деметры? - PullRequest
4 голосов
/ 09 апреля 2010

Следующий код нарушает Закон Деметры :

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 ]

3 голосов
/ 09 апреля 2010

Я думаю, что здесь есть две проблемы:

  1. Grades логика слишком сильно смешана с Student. Это должно быть сделано в Grades классе
  2. Teacher помещена в Student.

Вывод: ученик слишком много знает о внутренней структуре и логике Учителя и Классов, что нарушает LoD

2 голосов
/ 09 апреля 2010

Большинство проблем, таких как эта, могут быть решены путем пересмотра модели вашего домена.

Похоже, что у Студента гораздо больше ответственности, чем нужно. У него должна быть только одна причина для изменения.

Я бы реорганизовал это, добавив объект 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...
}
1 голос
/ 10 апреля 2010

Методы в классе ученика, которые нарушают закон Деметры:

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

потому что они выставляют доменные объекты Grades и Teacher к приложению.

Предполагая, что вы хотите продолжать скрывать оценки внутри ученика, а учителя - внутри классов, один из способов решения этой проблемы - определить прокси-методы (также называемые методами делегатов) в классе Student, которые работают с внутренними оценками и учителем объекты от имени приложения, аналогично методу Student.isTeacher(int, String). Это решение может привести к дублированию методов в классах и «Учитель в ученике», что является недостатком дизайна класса, который соответствует LofD.

Лучшим решением было бы убрать оценки и учителя из учеников и поместить их всех в другой класс, скажем, расшифровка:

class Transcript {
  Student student;
  Teacher teacher;
  Grades grades;
  Integer year;
}  
1 голос
/ 09 апреля 2010

Person.isTeacher "достигает" согласно статье в википедии, которую вы упомянули.

Я с удивлением обнаружил, что список оценок является собственностью студента. Разве это не должно быть то, о чем школа знает и управляет? Я спросил бы школу, какой учитель оценил ученика в каком году ...

0 голосов
/ 09 апреля 2010

Наличие этих двух приватных функций прерывает LoD.

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

Студентам не нужна логика для выполнения таких задач.

Я бы изменил дизайн так, чтобы отделить данные от логики. Студент должен быть только данные. Он должен содержать информацию только об ученике и ученике. Поэтому сюда не входят оценки, так как для этого понятия требуются другие предметы, такие как предмет и учитель.

То же самое касается учителя. Затем я бы создал место для хранения информации о классе и другое место для информации о предмете.

Для выполнения подобных задач я бы сделал это:

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

Где субъект также является объектом только данных.

...