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:
- The meaning of
ImageUrl
is lost. After all, it was theTeacher
‘sImageUrl
, not theStudent
‘s! We could rename the property toTeacherImageUrl
. - 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 fromStudent
(viaCourse
andClassroom
). Before we coupleTeacher
toStudent
, we may want to consider how this change will affect the system. - 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.
Leave a Reply
Want to join the discussion?Feel free to contribute!