Getter Method: Cheating the Spirit of The Law of Demeter
The Law of Demeter gives us suggestions on how to reduce coupling, but there are many loose ends from where we can break the clauses of the Law of Demeter.
Join the DZone community and get the full member experience.
Join For FreeEvery time I look at the getter methods, I wonder; it's a simple getter method, but its impact is very high on the code.
Is it a friend for developers or an enemy who is acting as a friend?
We can discuss various topics on getter, but here I will focus on one topic, which impacts the 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 end up with bad quality code. Today I am going to discuss how the getter method cheats the Law of Demeter's rules.
Note: I will not discuss the Law of Demeter principles. I assume you have a fair bit of idea of that, and I will just give a pointer on the Law of Demeter to show you the cheating.
What Does the Law of Demeter Say?
In layman's terms, it is saying never talk to strangers as strangers are a danger, and 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 class 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, and it tries to minimize 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, and if your degree of coupling is higher, then it becomes 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 friend (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 often see 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
xxxxxxxxxx
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:
xxxxxxxxxx
Employee deptHead = dept.getDeptHead();
String deptHeadName = deptHead.getName();//LOD Breaks here !!!!!
We have passed the Department object in build report method, so as per the Law of Demeter, we can talk to Department Object, so we can call its getter method, getDepartmentHead(), which returns an Employee Object which is a stranger to the buildReport method, so at this point, although we have not broken the Law of Demeter rule, Employee Object sneaks into Report Class and creates 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; in report, we may need the name of the Department head. The moment we call the getName method, it breaks the Law of Demeter, as it says methods need 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 the Reports code!
So, by getter actually, we did the cheating to get a third level Object Employee (Report > Department > Employee). Still, we can not do any useful thing with it without breaking the Law of Demeter. But no one gives attention to the 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 getters; they break encapsulation silently.
Now, let's make it more interesting.
Adding below code snippet in Department.java
xxxxxxxxxx
public String getDeptHeadName() {
return deptHead != null? deptHead.getName():null;
}
Then, call this method in the Department Report class buildReport method:
xxxxxxxxxx
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 the Law of Demeter. Departments should not do any operation on the Employee Objects field, it is Employee Object responsibility to do the formatting and all other operation on its file and get presentable data to the caller so, the caller should not do any operation on it.
Basically, the 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,
xxxxxxxxxx
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 are 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 from a class perspective; as per the 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 clauses of the Law of Demeter. Getter is one of those.
Use getters carefully. They may look simple but often break 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 are null, then you are in deep trouble. Adding multiple nulls check will not help you, it increases the complexity of your codes.
Conclusion
The 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 trick it, then there will be a debate, and may you win the debate but while losing the code quality. On the other hand, if you think logically and put programming reasoning first, then only you can thank the Law of Demeter.
Published at DZone with permission of Shamik Mitra, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments