Getters and setters are an illusion of encapsulation?

46

It is common to teach that it is right to leave class attributes private and to create getters and setters for them, all because of encapsulation.

Is not this the same thing as leaving everything public, since you can change and get the value freely? Does not this just create an illusion of encapsulation? Is it recommended or not? Why?

    
asked by Max 21.07.2014 в 12:57
source

4 answers

32

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.

    
answered by 21.07.2014 / 18:19
source
27

Using a setter is not an encapsulation illusion because the idea is that the class itself has full control over changing its properties.

If a property is naturally public, this control is simply non-existent and there is no encapsulation. Any external source can at any time change the property with any value of the appropriate type, and take the object to an improper state (considering what was planned by the designer).

Having a setter method for this, the object can - upon an update attempt - make necessary validations, update other dependent properties, etc., and thus ensure that the state is always correct as designed. >     

answered by 21.07.2014 в 13:13
17

At first it may seem that it makes no difference between leaving your public attribute or leaving it private with getters and setters without validations, as your access is free for modifications of both ways.

However if one day you realize that you must validate the attribute before assigning its value you will notice the difference of having opted for one of the two cases mentioned above. If you already have the getter and the setter you can do the validation inside your class without changing the classes that depend on them, but if you had defined your attribute as public and you change to private you will break all external classes that accessed the attribute freely.

Open-closed principle

According to the Open-Closed principle your code should be open for extension and closed for modifications, and by modifying your attribute from public to private you have hurt the principle because you can make other classes not even compile to the try to access the attribute; If you correct your class by validating the value before assigning it you did not actually hurt the principle, that's right, you did make a modification in your code, but based on Meyer's OCP this is acceptable because you are correcting what it can be called errors, and the classes that depend on it will still work, of course the behavior may change since the value used when calling the set () method may be different from that assigned within the setter implementation. >

See two examples of open-closed principle applications, one used in Polimorphic OCP and the other Meyer OCP: Open principle / closed - how to understand this?

    
answered by 21.07.2014 в 13:31
16

The advantage of using getters and setters is the ability to validate or modify data when using this pattern.

For example, suppose you have a Produto class with the preco attribute that receives values. Clearly, a negative value would be invalid. Therefore, setPreco(int preco) could behave as follows:

public void setPreco(int preco) {
    if (preco < 0) {
        this.preco = 0;
    } else {
        this.preco = preco;
    }
}

or:

public void setPreco(int preco) {
    if (preco < 0) {
        // exceção do tipo runtime
        throw new NumberFormatException("Preco deve ser maior do que zero.");
    }
    this.preco = preo;
}

Note that in the first example, the wrong value was simply corrected, and in the second instance a RuntimeException was thrown (assuming we are using java).

For getters, the logic is the same, if the value of the property to be retrieved is not suitable for any reason, it must be adjusted when it is returned to the client class.

    
answered by 21.07.2014 в 13:14