Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:
- O itself
- M's parameters
- any objects created/instantiated within M
- O's direct component objects
- a global variable, accessible by O, in the scope of M
Example
The following Java coded illustrated this law:public class LawOfDemeterInJava
{
private Topping cheeseTopping;
/**
* Good examples of following the Law of Demeter.
*/
public void goodExamples(Pizza pizza)
{
Foo foo = new Foo();
// (1) it's okay to call our own methods
doSomething();
// (2) it's okay to call methods on objects passed in to our method
int price = pizza.getPrice();
// (3) it's okay to call methods on any objects we create
cheeseTopping = new CheeseTopping();
float weight = cheeseTopping.getWeightUsed();
// (4) any directly held component objects
foo.doBar
}
public void badExamples(Pizza pizza)
{
// (5) Not OK. We are calling coock() on Cheese object
cheeseTopping.getCheese().cook();
// (6) Not OK
Slice slice = pizza.getSlice();
slice.decorate()
}
private void doSomething()
{
// do something here ...
}
}
What's wrong with writing this?
ReplyDeleteorderLine.getGroup().getOrder().getCustomer().getAddress().getPostalCode()
1) Hard to troubleshoot NullPointerException
ReplyDelete2) Hard to write unit test for it.
3) Not easy to debug
Unless it's chaining programming style code, eg. each method invocation return instance of same object...
Hey, thanks for such a good summary and putting things together.
ReplyDeleteI have noticed another thing in large projects. Your domain-specific object base grows, if you build dependency tree according to OOD & OOP patterns applied to these objects, you end up with a huge number of separate objects with "random" dependencies. Of course, they are not that random, but architecture starts having many shapes and it becomes difficult to maintain.
So one of solutions is to introduce service layer holding algorithms and functionality wrapped up into "managers" like Session.XYZObjectManager, Session.KLMObjectManager...
Hey,
ReplyDeleteNo problem, I just want to break my stereotypes again and move forward in TDD and all the stuff.
Definitely, facades eg. managers are really important party of any big application, especially frameworks.
I've often experienced functionality hell in outsourcing projects: tens or even hundred of services, without any entry point.
Is there an error in example #6 or it is general "not OK" case that even will not allow to compile code? =)
ReplyDeleteRrrichi, thank you for the correction, I made a mistake in example.
ReplyDeleteIt's "not OK" example because we violate Demeter Law calling method on 'child' object and we pass pizza as a parameter:
Slice slice = pizza.getSlice();
slice.decorate();