The Law of Demeter

The Law of Demeter aims to remove navigation trains (dot counting), and it also aims to provide good encapsulation with loosely coupled code.

A method that understands a navigation train breaks the Law of Demeter. For example, have a look at the following code:

report.Database.Connection.Open(); // Breaks the Law of Demeter.

Each unit of code should have a limited amount of knowledge. That knowledge should only be of relevant code that is closely related. With the Law of Demeter, you must tell and not ask. Using this law, you may only call methods of objects that are one or more of the following:

  • Passed as arguments
  • Created locally
  • Instance variables
  • Globals

Implementing the Law of Demeter can be difficult, but there are advantages to telling rather than asking. One such benefit is the decoupling of your code.

It is good to see a bad example that breaks the Law of Demeter, along with one that obeys the Law of Demeter, so we will see this in the following sections.

A good and a bad example (chaining) of the Law of Demeter

In the good example, we have the report instance variable. On the report variable object instance, the method to open the connection is called. This does not break the law.

The following code is a Connection class with a method that opens a connection:

namespace CH3.LawOfDemeter
{
public class Connection
{
public void Open()
{
// ... implementation ...
}
}
}

The Database class creates a new Connection object and opens a connection:

namespace CH3.LawOfDemeter
{
public class Database
{
public Database()
{
Connection = new Connection();
}

public Connection Connection { get; set; }

public void OpenConnection()
{
Connection.Open();
}
}
}

In the Report class, a Database object is instantiated and then a connection to the database is opened:

namespace CH3.LawOfDemeter
{
public class Report
{
public Report()
{
Database = new Database();
}

public Database Database { get; set; }

public void OpenConnection()
{
Database.OpenConnection();
}
}
}

So far, we have seen good code that obeys the Law of Demeter. But the following is code that breaks this law.

In the Example class, the Law of Demeter is broken because we introduce method chaining, as in report.Database.Connection.Open():

namespace CH3.LawOfDemeter
{
public class Example
{
public void BadExample_Chaining()
{
var report = new Report();
report.Database.Connection.Open();
}

public void GoodExample()
{
var report = new Report();
report.OpenConnection();
}
}
}

In this bad example, the Database getter is called on the report instance variable. This is acceptable. But then a call is made to the Connection getter that returns a different object. This breaks the Law of Demeter, as does the final call to open the connection.