Suppose, we have the following Boy class that tries to arrange a date with a Girl by analyzing her schedule (example in Java):
public class Boy {
public boolean tryArrangeDate(Girl girl, Date time) {
boolean success = true;
for (GirlRoutine routine : girl.getSchedule()) {
if (routine.happensAt(time)) {
success = false;
break;
}
}
return success;
}
}
Boy.tryArrangeDate() method clearly violates Law of Demeter because of routine.happensAt() call. One of the ways to resolve this is to move schedule analysis directly to Girl and avoid having a dependency on GirlRoutine. That would probably be one the best decisions in this case. RFC for Boy class will be reduced.
But suppose we choose a different direction for resolving violations of Law of Demeter and change the code in this way:
public class Boy {
public boolean tryArrangeDate(Girl girl, Date time) {
return isFree(girl.getSchedule(), time);
}
private boolean isFree(List<GirlRoutine> schedule, Date time) {
boolean free = true;
for (GirlRoutine routine : schedule) {
if (happensAt(routine, time)) {
free = false;
break;
}
}
return free;
}
private boolean happensAt(GirlRoutine routine, Date time) {
return routine.happensAt(time);
}
}
There are two private methods added that just delegate calls down to the Girl and her schedule / routines.
Each method taken individually does not seem to violate Law of Demeter (for simplicity reasons let us treat retrieval of item from collection as a primitive no-method-call operation). But overall we have not reduced RFC for this class, did not improve the cohesion, and actually increased WMC. Tell, don't ask principle is not preserved. So, Law of Demeter is satisfied but design is still flaky.
Question: Is it true that (formally) second code snippet does not violate Law of Demeter?
NOTE: Purpose of the question is NOT to find alternative solutions, but to confirm / refute that the solution adheres to the Law of Demeter
Update
Since you're just asking if the second still violates the Law of Demeter, then yes, I'd argue it does. No matter how you refactor
tryArrangeDate, it doesn't change the fact that it's calling a method fromGirlRoutine. When the Law of Demeter mentions "any method of an object", I take it that it refers to methods accessible to other objects, methods that are exposed to the "outside world". The private methods in your second code snippet are merely helper methods totryArrangeDate.Originally
The
Girlclass is the "expert" when it comes to its ownGirlRoutines. As much as possible, you must hide it from anyone else. Remember the principle of tell, don't ask.Perhaps you can do:
Don't read it like the Girl instance is asking out the Boy instance; the rule of thumb I follow (most of the time) is that the object from which you call the method is the direct object of the action that the method represents. In this case, the direct object of
askOutis the Girl instance.The
Responseclass can have information about how it went, or it can be something simple like:This way, a
Girlinstance has everything it needs to know to accept or reject theBoyinstance's request.