views:

182

answers:

2

I just recently became aware of the Law of Demeter.

Like a lot of things, I realized that it was something that I was already doing but did not have a name for. There are a few places though that I seem to violate it.

For example...

I might have an Address object:

public class Address : IAddress
{
   public string StreetAddress { get; set; }
   public string City { get; set; }
   public int Zip { get; set; }
}

and a Customer object:

public class Customer : ICustomer
{
   private IAddress address;

   Customer()
   {
      Address = null;
   }
   public string Name { get; set; }
   public IAddress
   {
      get
      {
         if (address == null)
         {
            address = new Address();
         }
         return address;
      }
      set
      {
         address = value;
      }
   }
}

Ok, this is fake code so you probably do not have to jump on me to use IoC to eliminate the new Address() or anything but it is pretty much an example of what I am doing. I did not include the interfaces as I am hoping they are obvious.

I would then use it in my code for stuff like int zip = customer.Address.Zip; and customer.Address.City = "Vancouver";

As I understand it, I am violating the Law of Demeter by manipulating details of Address from Customer.

Then again, it seems like the framework does as well. After all, wouldn't address.City.Length be a violation? Should I be adding methods to Address to handle accessing string properties? Probably not. So, why clutter up Address?

I cannot really just add methods to Address that relate only to customer. I have Member, Employee, Dependent, Vendor, Employer, etc. objects that all have addresses too.

Is there a better way to handle this? What kinds of problems am I risking if I use Address the way I am now?

For the Java folks, the Address class might look something more like the following if it helps:

public class Address extends AddressInterface
{
   private String m_city;

   public String getCity() { return m_city; }
   public void setCity(String city) { m_city = city; }
}

I must admit that customer.getAddress().setCity("Vancouver"); rings more alarms than customer.Address.City = "Vancouver"; did for me. Maybe I should switch to Java for a while.

+2  A: 

Hi,

Violations of the Law of Demeter are instances of a code smell named Inappropriate Intimacy. To remove this smell, you can refactor your code by hiding the internals of address and implementing methods in Customer that delegate to address. This way, you respect the encapsulation on the address inside the Customer.

Example:

public class Customer extends ICustomer{
    private Address address;
    ....

    public void setCity(String city){
        address.setCity(city);
    }

    public String getCity(){
        return address.getCity();
    }
}

Hope this helps.

Stephan
It also has the benefit if your adress implementation changes, you just have to maintain one class.
InsertNickHere
Actually, the major problem with this inappropriate intimacy is not in the Customer class itself. It is in the classes that use Customer. Any class that gets access to objects held by customer knows too much about Customer. Furthermore, it seems that Customer and address are some kind of anaemic classes, merely data clumps.
Stephan
+4  A: 

This article: http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx has a great explanation of the issues you are discussing.

As he notes it's not a dot counting exercise, it's a coupling issue. Currently your Customer and Address classes are too tightly coupled. For starters, Customer shouldn't be making new addresses, perhaps pass an Address in using a constructor. As to whether you should be using multiple dots to access parts of the address, read the article ...

Martin Fowler: "I'd prefer it to be called the Occasionally Useful Suggestion of Demeter."

Hightechrider
Uuuh, i DO like that quote :D
atamanroman
@Hightechrider - Thank you for posting this as an answer. The quote sums up the article pretty well.
Justin