Strategies for refactoring to the Law of Demeter
29 May, 2009 § Leave a comment
The Law of Demetre (LoD), or Principle of Least Knowledge, is a design guideline for developing software, particularly object-oriented programs. The guideline was invented at Northeastern University towards the end of 1987, and can be succinctly summarized as “Only talk to your immediate friends.” The fundamental notion is that a given object should assume as little as possible about the structure or properties of anything else (including its subcomponents).
Some code that I have ran across breaks the Law of Demeter. It just didn’t break it, it had complete disregard for the law. In working on some refactorings to open up unit test coverage, I worked through several different design alternatives before coming up with the final choice.
Example problem: There are quite a few lines of the codebase that look like this,
CString strUserName = theApp.GetSomeObject().GetOwner().strUserName;
In this case, there is only one instance of the SomeObject class during the execution of the program. It is referenced using the global CWinApp-derived instance, theApp.
First idea: Use the singleton pattern. This pattern is considered an anti pattern by some, and is known to make unit testing harder since it can make the process of mocking out the object non-trivial. I quickly moved away from this decision.
Second and final idea: Use dependency injection. When the SomeObject is created within the constructor for the CWinApp-derived instance, any object that needs a reference to the object gets a reference. I was then able to make SomeObject implement an interface that the mocks can use. The references are then passed down to all parties that need this. This makes methods and classes easy to unit test and reduces some coupling, since now the code can look like this:
CString strUserName = m_pSomeObject->GetOwner().strUserName;
So we’ve gotten rid of the call to theApp, but how do we get rid of the call to the strUserName property? In this case, we can define a method within SomeObject’s interface to get the username of the owner.
CString strUserName = m_pSomeObject->GetUserNameOfOwner();
If you find yourself writing a lot of simple one line methods to access properties of an object like the Owner, then this last solution probably isn’t the best route for you to take, but it might give you an idea.
Thanks, and let me know your thoughts.