Question

Say you have a class, Car, which has a Driver. If you wanted to access the driver's age, you would do:

@car.driver_age

Instead of

@car.driver.age

If you have delegated the driver's age attribute in the Car model (with prefix set to true).

However, if you also had a Passenger class and you wanted to access the number of passengers in the car, is the following not breaking the Law of Demeter, or is my thinking over-zealous:

@car.passengers.count
Was it helpful?

Solution

I think that count is so general that i would not find it necessary to proxy the call. I would ask myself the question:

Is it possible that there will be an implementation of passengers in the future, that will not respond to count?

Since passengers is extremely likely to be a container type forever, and all container types in Ruby (Array, Hash, …) respond to count in the way you would expect, i would answer this question with “no” and therefore stick with @car.passengers.count.

EDIT

But if you’re being strict, you are indeed breaking the Law of Demeter. Consider for example a class RobotCar < Car that has no passengers at all. Now, following LoD you could simply return 0 from the method car.passenger_count, whereas when not following LoD you would have to return an empty container from passengers in order not to break other code.

In the end, you will have to decide for yourself just how likely it is that the interface will ever change. If you are very certain that it won't ever change, then i guess it's ok to disobey LoD.

OTHER TIPS

If your class/method needs to know the driver's age, it should have a direct reference to the driver:

@driver.age

Or to the array of passengers:

@passengers.count

Accessing these through @car makes many assumptions. Imagine an automatic car without a driver or a toy car without passengers. @car.driver_age or @car.passengers_count wouldn't make much sense.

LoD isn't just "counting dots", and trading an underscore for a dot doesn't help.

Cars have a driver that have an age; there's nothing unreasonable about this.

(Well, not really, because we're about to enter an age of driverless cars and this model may not account for that, but that's a separate issue.)

The Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:

  1. O itself
  2. M's parameters
  3. any objects created/instantiated within M
  4. O's direct component objects

In particular, an object should avoid invoking methods of a member object returned by another method.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top