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
Girl
class is the "expert" when it comes to its ownGirlRoutine
s. 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
askOut
is the Girl instance.The
Response
class can have information about how it went, or it can be something simple like:This way, a
Girl
instance has everything it needs to know to accept or reject theBoy
instance's request.