Trying to understand the Law of Demeter as it applies to my code

493 views Asked by At

I have a simple Store class that contains an Inventory. The Inventory contains a list of Items. In order to modify one of the Items in the Inventory, I'd have to write:

Store store( /*parameters*/ );
store.accessInventory(/*password*/).accessItem(/*item name*/).setPrice(9.50);

As I understand it, this breaks the Law of Demeter because Store has to reach through Inventory and into Item in order to call setPrice().

I'd like to reconcile this violation of the law with the violation of the law in the classic example with the paper boy and the customer. In the paper boy example, the paper boy "knows" too much about the customer by assuming he will make his payment with a wallet. If the customer's method of payment changes, the paper boy will have to change as well.

What assumptions in my code are being made that could result in a problem like the one encountered in the paper boy example?

I understand that the Law is really more of a guideline, and that abiding by it in this case may not be the best idea, but I'd like to at least understand the Law before I move on. Thanks.

3

There are 3 answers

6
Jeremy Friesner On

Your code is assuming that the Inventory object is the only object that will ever need to be notified when a price changes.

Imagine that in addition to containing an Inventory of items, your Store also had some advertising posters hung up in its windows.

If you followed the law of Demeter, your Store object might have a nice method like this:

void Store :: SetItemPrice(string item_name, float item_price)
{
   inventory.SetItemPrice(item_name, item_price);

   for (int i=0; i<num_advertising_posters; i++)
   {
      // Update any posters with the new price!
      if (advertising_posters[i].advertised_item == item_name)
      {
         advertising_posters[i].SetAdvertisedPrice(item_price);
      }
   }
}

... but if you instead allow the calling code to access the inventory object directly, then there is no easy/foolproof way to make sure that the advertisements always get updated whenever a price gets updated, so chances are that at some point your store's advertising posters will show an old/wrong price for a product. The Law of Demeter makes it easier to avoid that sort of bug.

3
Paari Kandappan On

Your example follows the paperboy example very closely. Your code is dependent upon the current Item interface which has the method setPrice(float). If you change that interface you need to update

store.accessInventory(password).accessItem(name).setPrice(price)

everywhere that it occurs.

A better solution would be to create function for Store and Inventory of the form

void Store::setItemPrice(string password, string name, float price)
{
  accessInventory(password).setItemPrice(name, price);
}

void Inventory::setItemPrice(string name, float price)
{
accessItem(name).setPrice(price);
}

This way you can use those functions in the rest of your code and just change them accordingly if your Item or Inventory interfaces change.

0
David Hammen On

What assumptions in my code are being made that could result in a problem like the one encountered in the paper boy example?

Angry customers. Angry personnel. Angry managers. Angry accountants.

Customers don't mind being surprised when the price listed is higher than the price they are charged, but they sure do get POed when they are charged a higher price than the price they expected. The worker bees don't like it when angry customers come up to them because the stupid newbie store manager didn't follow protocol and changed the price directly in the inventory. Low and mid level managers don't like this either because they get grief from all sides. Bean counters also like to be informed when the value of their beans suddenly change.

It's not just the advertising posters that Jeremy mentioned in his answer. Some person needs to be told to change the little pricing tags next to the stack of items that specify the price. A crew of people need to be dispatched with portable printers to change the price stamped on each item of that type. These people need to be scheduled, and you had better not do that without talking to the department manager. And so on and so on. Reaching through the inventory to change the price is a bad, bad idea.

BTW, all of the above is coming from someone who thinks the Law Of Demeter is better called the Occasionally Useful Suggestion of Demeter.