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.
The Law of Demeter reduces dependencies and helps build components that are loosely coupled so that code is easier to reuse, maintain, test, and refactor. Violating it by using a long chain of object calls is like a pyramid of cards — it can fall easily.
High Cohesion (HC): Adhering to the Law of Demeter often results in additional methods that mirror methods of aggregated objects. As these objects have other responsibilities, the additional methods have fewer commonalities with the “real” methods of the class, which results in a lower cohesion.
getObjectC(). display() this sort of statement is a violation of Law of Demeter. There are primarily 4 principles of the least knowledge in java as follows: Method M of an object O can invoke the method of O itself.
It is so named for its origin in the Demeter Project, an adaptive programming and aspect-oriented programming effort. The project was named in honor of Demeter, “distribution-mother” and the Greek goddess of agriculture, to signify a bottom-up philosophy of programming which is also embodied in the law itself.
The Law of Demeter (LoD) or principle of least knowledge is a design guideline for developing software, particularly object-oriented programs. This law was proposed by Ian Holland in 1987. Holland and colleagues were programming a system called Demeter using oriented object programming.
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."
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.
The problem here is that Address is a ValueObject. You would never change the city without changing the zip.
public class Customer extends ICustomer{
private Address address;
....
public void setAddress(String street, String city, int zip){
address = Address.new(street, city, zip);
}
// or even better but i'm not sure if it's valid C#
public void setAddress(int zip){
address = Address.lookup(zip);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With