Law of Demeter Coding Violations & How to Fix Them

0
The article lists down Law of Demeter Violations and presents solutions on how to fix them. The code samples are written in Java. Feel free to share your comment, if any.
What is Law of Demeter Principle?

There are several good pages on the web which could be read to understand the object-oriented principle, Law of Demeter. Following are some of them:

The group of programmers working on a Demeter system, back in 1980, came up with this programming principle which they termed as Law of Demeter. According to them, this principle achieves key programming objectives such as loose coupling and high maintainability in terms of programmers.

For all classes C. and for all methods M attached to C, all objects to which M sends a message must be instances of classes associated with the following classes:

  • The argument classes of M (including C).
  • The instance variable classes of C.

(Objects created by M, or by functions or methods which M calls, and objects in global variables are considered as arguments of M.)

Simply speaking, Law of Demeter suggests what methods could be called from within any method of a class.

  • Methods on member variable of the class
  • Methods on objects that are created within the method
  • Methods on objects passed as argument to the method
  • Methods of the same class

In my experience, I have come across very less number of programmers who have got a clear understanding of this principle. As a matter of fact, those using static code analysis tool such as PMB have been found to be not paying attention to this principle. However, it is worth paying attention to some of the coding violations related with this principle.

Following are two most common violations for Law of Demeter. These violations can be observed in your code by using static code analysis tool such as PMB. If you are a Java developer, and you use Eclipse IDE, you could get started quickly by downloading PMB eclipse plugin.

  1. Object Not Created Locally
  2. Method Chains Calls
Violation 1 (as per PMB): Object Not Created Locally

This violation relates to the fact that method is called on the object which is not created within the method and rather, retrieved as a return object as a result of method invocation on one of the local objects.

In the code below, multiple statements consisting of result.isSuccess() ¬†represents violations as the method call, isSuccess(), is made on the object, result, which is not created within recordNewApplication method shown below, but retrieved as a return object from different method calls such as applicationValidation.validate and admissionApplicationDao.persist. The following method when executed against PMB static code analysis tool threw the violation such as “Object Not Created Locally”. Check the PMB page for greater details.

 

       public ApplicationResult recordNewApplication( Applicant applicant ) {				
		ApplicationResult retResult = new ApplicationResult();

		ApplicationResult result = applicationValidation.validate( applicant ); 
		if( result.isSuccess() ) { //Note isSuccess()
			result = admissionApplicationDao.persist(applicant);
			if( result.isSuccess() ) { //Note isSuccess()
				retResult.setSuccess( true );
				retResult.setMessage( "Admission application successful" );
			} else {				
				retResult.setMessage( result.getMessage() ); //Note getMessage ()
			}
		} else {			
			retResult.setMessage( result.getMessage() ); //Note getMessage()
		}													
		return retResult;
	}

To fix the above violation, following changes were made:

  • Instead of returning ApplicationResult object, returned the boolean.
  • And, in case of any error message retrieved from result object, retrieved the error message using getMessage on objects such as applicationValidation and admissionApplicationDao. From implementation perspective, the ApplicationResult object is maintained within the respective objects and not returned.

 

        public ApplicationResult recordNewApplication( Applicant applicant ) {		
		ApplicationResult result = new ApplicationResult();
		boolean valIsSuccess = applicationValidation.validate( applicant ); 
		if( valIsSuccess ) {
			boolean perIsSuccess = admissionApplicationDao.persist(applicant);
			if( perIsSuccess ) {
				result.setSuccess( true );
				result.setMessage( "Admission application successful" );
			} else {				
				result.setMessage( admissionApplicationDao.getMessage() ); //Note getMessage()
			}
		} else {			
			result.setMessage( applicationValidation.getMessage() ); //Note getMessage()
		}													
		return result;
	}

 

Violation 2 (As per PMB): Method Chain Calls

This violation relates to the method invocation which is made on a series of method invocations as evident in the code sample below. Interestingly, I have found many a programmer using such method invocations.

Following piece of code represents another Law of Demeter Violation termed as Method Chain Calls.

 

public ApplicationResult validateLastName(Applicant applicant)  {
		ApplicationResult result = new ApplicationResult();
		result.setSuccess( true );
		if( applicant.getLastName().trim().length() == 0 ) { //Note method chains
			result.setMessage( "Lastname can not be empty" );
			result.setSuccess( false );
		}
		return result;
	}

The fix to above code violation is fixed using following code. Note that the validation related to lastname being non-empty is moved within Applicant object method, named as isValidLastName().

 

        public ApplicationResult validateLastName(Applicant applicant)  {
		ApplicationResult result = new ApplicationResult();
		result.setSuccess( true );
		if( applicant.isValidLastName() ) {// Note isValidLastName
			result.setMessage( "Lastname can not be empty" );
			result.setSuccess( false );
		}
		return result;
	}

 

Lessons Learnt to Avoid Coding Violations of Law of Demeter
  1. Avoid getting data from invoking methods on retrieved objects from method invocations on local objects. Instead, implement method on local objects that returns the required data. See the example of result.getMessage() vis-a-vis applicationValidation.getMessage in above examples.
  2. Avoid method chain calls due to various reasons such as following. Instead try implementing method on the object to get the work done.
    • It can lead to NullPointerExceptions
    • It could also lead to difficulty in mocking.

[adsenseyu1]

Ajitesh Kumar
Share.

Comments are closed.