The Law of Demeter (LoD), or Principle of Least Knowledge, is a design guideline for developing software, particularly object-oriented programs. (wikipedia)
While everyday working on code that was written by lazy coders or junior coders I see a lot of violation of this law. I think every programmer should know the Law of Demeter by heart, as it states.
Any method of an object should call only methods belonging to:
1. Itself
2. Any parameters that were passed in to the method
3. Any objects it created
4. any directly held component objects
Quite simple one may think, in fact it is simple and here is an example of it
public class Person
{
//Here is a directly held component of the class
private readonly PhoneBook _phoneBook;
public Person(PhoneBook _phoneBook)
{
this._phoneBook = _phoneBook;
}
public void AddCellNumber(string number)
{
//You can call any parameters that were passed in to the method
var length = number.Length;
//creating an object so its methods are legal
var phoneNumber = new PhoneNumber();
//can call method on any objects it created
if (phoneNumber.isValid(number) && length > 7)
{
//one can a method on the component of the object
_phoneBook.Add(number);
//call a local method within object
PrintNumber(number);
}
}
//call a local method within object
public void PrintNumber(string number)
{
}
}
Now if only people would follow these principles, but the sad part is this is how I see most people just going about and violating the principle.
public void ShowPhoneNumber(PhoneBook phoneBook)
{
//valid since we are calling something passed in as parameter
var phoneNumber = phoneBook.GetNumber("John");
//here is where it goes wrong
//we don't own phone number and it wasn't pass to us
var withAreaCode = phoneNumber.GetNumberWithAreaCode();
Console.WriteLine(withAreaCode);
}
So how do we fix this, so that it doesn’t violate the principle.
public void ShowPhoneNumberBetter(PhoneBook phoneBook)
{
//valid since we are calling something passed in as parameter
var withAreaCode = phoneBook.GetNumberWithAreaCode("John");
Console.WriteLine(withAreaCode);
}
By having phoneBook return us the withAreaCode, we reduce the number of class we are dependent on, and if anything changes in PhoneNumber this class/method would not be affected, only one place to change.
Next time if you see someone using code that violates the principle (wack them in the head first and then refer them here), remember to use an analogy I used with my co-worker.
- I told him, I know you and your cell number, but would you think it would be okay for me to go through your contacts and get your girlfriend’s number?
- Don’t you think that there is something wrong with it that?
- I should only be able to get her number if I request it from you. (if he is willing to give me that is)
- Not going through your contact list, what if your contact list changes? (Now he stores it in Outlook but what if he changes it to using pen and paper)
- Does that mean when I call outlook contact list I am looking at your ex-girlfriend’s number? Since you moved to pen and paper?
- Why am I dependent on your contact list? I only know you, shouldn’t I be able to just ask you for it and wherever you store it, is not my problem.
- All you have to do is give me the number or return me nothing and life goes on.
Last but not lease always remember to question and review code, find out, why is this part dependent on that part? Why is there a call to something that feels like couple of level’s down, (i.e ObjectA.ObjectB.ObjectC.methodZ ) once you see that you know there is something fishy there, and own it to yourself to refactor and change it.