I agree with all the answers. Getters and setters are essential.
But the question is: are they always needed?
What really needs to be accessed?
It is common practice to create getters and setters for all properties of a class. It is not reflected on the actual need or on possible side effects thereof.
Many methods are created unnecessarily, perhaps thinking about what may be needed someday, but they are never used. This only leaves the code more prone to errors.
And the interface?
Although setters and getters are an encapsulation type of the attribute, the public method signature is part of its interface, being a type of "contract" with the other classes.
The attribute may be encapsulated, but in no way are you free to change implementations, as any attribute change will likely affect the signature of some method as well.
What about complex objects?
For example, if my class has a list:
public class Turma {
private List<Aluno> alunos;
}
What to do? Put a setAlunos
?
public class Turma {
private List<Aluno> alunos;
public void setAlunos(List<Aluno> alunos) {
this.alunos = alunos;
}
}
Or manage the list internally?
public class Turma {
private List<Aluno> alunos = new ArrayList<Aluno>();
public void addAluno(Aluno aluno) {
alunos.add(aluno);
}
}
There are several situations where it is best not to have the setter method.
In the first example, the list is "exposed". It is possible that the implementation of the list passed by another developer does not have some internally used method implemented. For example, if our class adds students at some point, but the last list is immutable.
Immovable Objects
In scenarios where a business object is shared between several threads, setters may cause unwanted effects. Immutable objects (without setters ) are much safer and more efficient in that respect, as they can not end up in an inconsistent state due to competition.
In addition, if an object is passed to multiple routines and services, setters may be inadvertently called by some routine leaving the object in an inconsistent state. Suppose you have already applied all of the validation rules, but before writing the data from the database one of the routines calls a set . Then you need to "hunt" who was responsible for the change.
One more point is that some objects could benefit from cache information. For example, if one of the attributes is calculated from several others. But the various setters make this implementation much more complex.
Creating an immutable object is not difficult. One way is to allow values to be defined through the constructor and not have set methods. Example:
public class Turma {
private List<Aluno> alunos;
public Turma(List<Aluno> alunos) throws ListaDeProblemasException {
this.alunos = alunos;
//valida e processa alunos como bem quiser
//sabe-se que não irá mudar depois
}
public List<Aluno> getAlunos() {
return alunos;
}
}
Setter validation?
Using setters for validation is interesting to some extent.
This can actually become a problem in cases where one attribute depends on another. Imagine, for example, that you have a setCPF
method and a setCNPJ
method. Both can only be called, respectively, if the type of person is F
or J
. What if someone decides to call those before them?
In addition, it is much more difficult to handle this type of error to, for example, display the list of errors for the user on the screen.
Conclusion
Getters and setters may be, rather, an illusion of encapsulation in many cases, mainly because public methods of a class increase the coupling and the "commitment" to keep all those methods.
It's not that it's an illusion by itself, but it happens in the minds of programmers who think that encapsulamento = getter + setter
. They will later discover "strange" behaviors in the program because there is really nothing "hidden".
An implementation with the least public method will make the code more "secure" and flexible.