Posts Tagged ‘programming’

The Law of Demeter

Saturday, May 10th, 2008

The other day I came across a reference to something called the law of demeter. With much sadness, I realized that I could not remember what that law was. It sounded familiar, and was probably an answer to some test question in college. Nonetheless, I had forgotten it, and I felt that it was my duty to look it up.

Wikipedia had a nice page[1] on it, and I was happy to know that I was following this policy already. In fact, the concept is core to well encapsulated code and a good domain model.

It’s a shame that it has such a pedantic sounding name; I don’t see myself being able to tell someone that their code would better if they only followed the law of demeter. Principle of least knowledge sounds better, but it’s still kind of vague. Unfortunately, it’s a very commonly violated principle, but it is one that should guide our default programming behavior. That is, when we aren’t being forced to violate it because of an api or legacy code base.

Anyway, to summarize what it is, it basically says that an object A can only use other objects that are fields, parameters to a method, or created inside of A. Here is a nicely contrived example of violating this principle:

  1. class Book {
  2.     double cost;
  3.     public double getCost() { return cost; }
  4. }
  5.  
  6. class ShoppingCart {
  7.     List<Book> books;
  8.     public List<Book> getBooks() { return books; }
  9. }
  10.  
  11. public class SalesCalculator {
  12.     public void calculateTotalCost(ShoppingCart cart) {
  13.         double total = 0;
  14.         for (Book item : cart.getBooks()) {
  15.             total += item.getCost();
  16.         }
  17.         System.out.println(“Total cost is: “ + total);
  18.     }
  19. }

Actually, this isn’t that contrived. For some reason, people love putting calculations into a class with Calculator in the name. In this example, SalesCalculator knows about more than just the ShoppingCart it’s given. It knows about the internals of the shopping cart. Not only does it know that it has books, but that it stores the books in a List. Now, the getter provides a slight appearance that it doesn’t really know that it’s stored in a list, but in this example, it’s returning the exact list object that it is storing internally. In this situation, if I modify the list outside of the ShoppingCart, then it’s internal state changes. We may as well be accessing books by doing a cart.books and leave out the getter code.

I’m digressing here; there is probably some other elitist sounding principle that basically says that I should not be able to mutate an objects internal state from outside the object. An improved version of the code would look like:

  1. class Book {
  2.     double cost;
  3.     public double getCost() { return cost; }
  4. }
  5.  
  6. class ShoppingCart {
  7.     List<Book> books;
  8.     public double calculateTotalCost() {
  9.         double total = 0;
  10.         for (Book book : books) {
  11.             total += book.getCost();
  12.         }
  13.         return total;
  14.     }
  15. }
  16.  
  17. public class SalesCalculator {
  18.     public void calculateTotalCost(ShoppingCart cart) {
  19.         System.out.println(“Total cost is: “
  20. + cart.calculateTotalCost());
  21.     }
  22. }

That’s better. Now SalesCalculator knows nothing about Book objects, nor is it playing around with the List that shopping cart was using to hold the books. In fact, it looks like the SalesCalculator barely has a reason to exist. And it probably shouldn’t, not as a calculator. Maybe it could be a SalesPrinter or something.

The benefit of this increases as the logic of a domain model grows. Another common smell are objects like Managers:

  1. class ShoppingCart {
  2.     List<Book> books;
  3.     int numberOfComicBooks;
  4.     public List<Book> getBooks() {
  5.         return books;
  6.     }
  7.     public int getNumberOfComicBooks() {
  8.         return numberOfComicBooks;
  9.     }
  10.     public void setNumberOfComicBooks(int numberOfComicBooks) {
  11.         this.numberOfComicBooks = numberOfComicBooks;
  12.     }
  13. }
  14.  
  15. class ShoppingCartManager {
  16.     public void addBookToCart(ShoppingCart cart, Book book) {
  17.         cart.getBooks().add(book);
  18.         if (book.isComicBook) {
  19.             cart.setNumberOfComicBooks(
  20. cart.getNumberOfComicBooks() + 1);
  21.         }
  22.     }
  23. }

Why can’t the Shopping cart manage the adding of books and counting of comic books itself? If it did we would have less code anyway:

  1. class ShoppingCart {
  2.     List<Book> books;
  3.     int numberOfComicBooks;
  4.  
  5.     public void add(Book book) {
  6.         books.add(book);
  7.         if (book.isComicBook()) {
  8.             numberOfComicBooks++;
  9.         }
  10.     }
  11. }

Some developers have a default behavior that results in less code following the law of demeter (and tosses encapsulation in the garbage). That is, when they create an object, they immediately have their IDE generate getters and setters for all the fields they added. I think the idea is that it will save them time later or some nonsense like that. The unfortunate reality is that when I begin changing the ShoppingCart class, I’m going to have to traverse a tangled web of references across the code base trying to figure out what other objects are holding onto the ShoppingCarts book list and changing it on me. It gets even worse if you introduce multiple threads in to the mix.

[1] http://en.wikipedia.org/wiki/Law_of_Demeter