Fixing The Law Of Demeter – Forwarding Calls

 

Yesterday we examined The Law of Demeter and why violations may cause problems in our code. Today I would like to drill into a solution to some Law of Demeter violations—Forwarding Calls.  

Say, we have a class SalesOrderLine:

  public class SalesOrderLine
  {
     public int Quantity { get; }
     public Product Product { get; }

     public SalesOrderLine(int quantity, Product product)
     {
        Quantity = quantity;
        Product = product;
     }

     /// ...
  }

Simultaneously, class Product has a UnitPrice:

  public class Product
  {
     public decimal UnitPrice { get; }

     /// ...
  }

It’s conceivable that code might refer to the UnitPrice in SalesOrderLine as

  var unitPrice = salesOrderLine.Product.UnitPrice;

We have two dot operations and are breaking the Law of Demeter.

What are we to do?

Well, one elegant solution to this problem is for us to add a forwarding property[1] onto SalesOrderLine:

  public decimal UnitPrice => Product.UnitPrice;

Now we may use 

  var unitPrice = salesOrderLine.UnitPrice;

Isn’t that nicer? Yes—and it complies with Demeter’s Law. 

In this instance, pulling UnitPrice up a level, from Product to SalesOrderLine, made sense—it’s clear what salesOrderLine.UnitPrice means.

However, that is not always the case.

For example:

  var url = student.Course.ClassRoom.Teacher.ImageUrl;

Let’s forward the ImageUrl property onto class Student:

  var url = student.ImageUrl;

That might work. However, there are problems:

  1. The meaning of ImageUrl is lost. After all, it was the Teacher‘s ImageUrl, not the Student‘s! We could rename the property to TeacherImageUrl.
  2. We may also have a semantic infringement: In the modelling of this eLearning system, there may be a good reason why Teacher is so far removed from Student (via Course and Classroom). Before we couple Teacher to Student, we may want to consider how this change will affect the system. 
  3. We are still infringing on the Law of Demeter. All we have done is moved the violation inside the property:
   public string TeacherImageUrl => Course.ClassRoom.Teacher.ImageUrl;

Still too many dot operators.

Forwarding properties and methods are a great way to fix low-level Demeter violations. However, this is a cure that we ought to apply with caution since it can create subtle coupling problems.

 

Footnotes:

[1] This approach works with methods too. E.g. GetUnitPrice(). Having said that, a property seems more elegant in this case.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply