Every time I look at the Getter methods, I wonder, a simple getter method but its impact is very high on the code.
Is it a friend for developers or enemies who are acting as friends?
We can discuss various topics on Getter but here I would focus on one topic, which impacts codebase severely and forcibly implementing coupling and breaching the encapsulation.
The most interesting part is that in some cases Getters can cheat the “Law of Demeter” rules, welcome coupling, and breach encapsulation.
So it creates confusion for developers and as an outcome, we ended up with bad quality code. Today I am going to discuss how getter method cheats the “Law of Demeter's” rules
Note:: I will not discuss “ Law of Demeter “ principles, I assume you have a fair bit of idea of that, I will just give a pointer on Law of Demeter so I can show you the cheating.
What is Law of Demeter say::
In layman's terms, it is saying never talk to strangers as strangers are a danger, only talk to your friends.
So, in technical terms, a method can only interact with its arguments, it’s holding class instance variables, Objects which are created inside the method context, and static variables in java.
More precisely, For any class C, a method M belonging to C may only invoke the following:
- The object class C itself
- Members of class C
- An argument of the method M
- An object created within the method M
- Global objects
Rules are very clear and specific, it tries to minimize the communication /
If you restrict your communication with passed arguments and the class instance variable then you are reducing the coupling, more communication means more coupling, if your degree of coupling is higher the obvious you are breaching encapsulation.
Although, Law of Demeter tries to secure encapsulation by enforcing the law “Talk to immediate friends not to any strangers” -- but our good(really?) The getter method can trick it, getter will maintain all the laws but humiliate the Law of Demeter by cheating.
Let’s take a regular example which we can see often in the codebase.
Department.java
public class Department {
private Long deptId;
private Employee deptHead;
private String deptName;
public Long getDeptId() {
return deptId;
}
public void setDeptId(Long deptId) {
this.deptId = deptId;
}
public Employee getDeptHead() {
return deptHead;
}
public void setDeptHead(Employee deptHead) {
this.deptHead = deptHead;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
DepartmentReport.java
package blog.javaonfly.article.getter;
public class DepertmentReport {
public void buildReport(Department dept) {
/*
* As per LOD Ok , but what is the use of doing that--???????
* Why are you cheating LOD spririt.
*/
Employee deptHead = dept.getDeptHead();
String deptHeadName = deptHead.getName();//LOD Breaks here !!!!!
System.out.println("In Report" + dept);
}
}
Now , inspect these two lines
Employee deptHead = dept.getDeptHead();
String deptHeadName = deptHead.getName();//LOD Breaks here !!!!!
We have passed the Department object in build report method, so as per Law of Demeter we can talk to Department object, so we can call it’s getter method, getDepartmentHead() , which return an Employee Object which is stranger to buildReport method, so at this point, although we have not broken the Law of Demeter rule but Employee Object sneak in Report class and create a coupling!!!
Think logically, is it the Report object’s responsibility to deal with the Employee Object?
The answer is obviously no, but then what do we do with only Employee Object in Report class? Employee Object is not useful if we do not dig into it as in report we may need the name of the Department head, the moment we call getName method it breaks the Law of Demeter as it says method needs to only interact with arguments, Rule 3.
So, dept.getDeptHead().getName(); is not permissible according to the law, and it is good as you do not know Employee is null or not in buildreport method if it is null, it will break Reports code!!!
So, By getter actually, we did the cheating to get a third level Object Employee(Report -> Department->Employee), but we can not do any useful thing with it without breaking Law of Demeter, But no one gives attention to Law of Demeter and we break the Law of Demeter, by happily calling a chain of getter methods.
This is one reason I do not like Getter's, it breaks encapsulation silently.
Now, let's make it more interesting.
Adding below code snippet in Department.java
public String getDeptHeadName() {
return deptHead != null? deptHead.getName():null;
}
Then , call this method in Department Report class buildReport method
String deptHeadName = dept.getDeptHeadName();
Now, Again according to the Law of Demeter it is perfect. The Department only talks to an instance variable department Head(Rule 2), and Report class told to method arguments(Rule3).
But again, we are breaking the spirit of Law of Demeter, Departments should not do any operation on Employe objects field, it is Employee Object responsibility to do the formatting and all other operation on it’s filed and get presentable data to the caller so, the caller should not do any operation on it.
Basically, Caller will not ask for data it will command the associate class for readymade data.
Tell don’t ask principle.
In this example you are asking, getter methods are asking for data that means asking for more responsibility to properly handle them, which is not your duty at all.
Now, what about this case,
public void buildReport(Department dept) {
Employee deptHead = dept.getDeptHead();
String deptHeadName = getDepartmentHeadName(deptHead);
System.out.println("In Report" + dept);
}
private String getDepartmentHeadName(Employee emp) {
return emp.getName();
}
Again, we did some trickery, we maintained the Law of Demeter but cheating its essence!!!
Now, we create a private method and pass the Employee object as an argument and call geName in that method, now as per Rule 3 we are good, but think on class perspective, as per Law of Demeter we should talk to immediate friends which is Department Object but here again We are talking to Employee Object.
What do we learn from this?
- We learn that the Law of Demeter is giving us suggestions on how to reduce coupling and be safe by not talking to strangers but there are many loose ends from where we can break the naive clause of Law of Demeter, Getter is one of those.
- Use Getter carefully, it may look simple but often breaks encapsulation by exposing a Has-A relationship to the Outerworld.
- Do not write getter for HAS-A relationship, it means you are delegating the responsibility to the caller or Higher level methods.
- Calling getter Chain is bad if each getter returns different Objects, because if any of the values is null then you are in deep trouble, adding multiple nulls check will not help you, it increases your complexity of codes.
Conclusion:: Law of Demeter is good when you take it as a suggestion, but if you technically try to prove you are maintaining the laws and tricks it, then there will be debate and may you win the debate but losing the code quality, on other hand, if you think logically put programming reasoning then only you can thank “Law of Demeter”.