How does this code violate the Law of Demeter?

The following code violates the 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; } } 

Questions

  • How is LoD broken?
  • Where is the code that violates LoD?
  • How should code be written to support LoD?
+4
source share
5 answers

Methods in the class Student violating the Law of Demeter,

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

because they expose domain objects to classes and the teacher in the application.

Assuming that you want to continue to hide classes inside the student and teacher inside the classes, one way to resolve this problem is to define proxy methods (also called delegate methods) in the Student class that work with inner classes and teachers objects on behalf of the application, similar to the method Student.isTeacher(int, String) . This solution can lead to duplication of methods in classes and teachers in Student, which is a disadvantage of class design that conforms to LofD.

The best solution would be to remove the Grades and the Teacher from the Student and put them all in another class, for example Transcript:

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

I think there are two problems here:

  • Grades logic is too much mixed up with Student . This should be done in the Grades class.
  • Teacher logic is placed in Student .

Conclusion: the student knows too much about the internal structure and logic of Teacher and Classes and what breaks LoD

+3
source

Most of these problems can be resolved by revising your domain model.

The Student seems to have more responsibility than necessary. He should have only one reason.

I would reorganize this by adding a ReportCard object.

 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
source

Person.isTeacher "reaches" according to the wikipedia article you mentioned.

I was surprised to find that the list of classes is the property of the student. Isn't that what the school knows and controls? I would ask the school that the teacher graduated the student that year ...

+1
source

If these two private functions break LoD.

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

Students do not need logic to perform such tasks.

As I redesigned this, you need to separate the data from the logic. The student must be purely data. It should contain information only about the student and student. Therefore, this does not include classes, since this concept requires others, such as the subject and teacher.

The same goes for the teacher. Then I created a place to store information about the class and another place for information about the subject.

To perform such tasks, I would do the following:

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

If the object is also a data-only object.

0
source

Source: https://habr.com/ru/post/1306495/


All Articles