Evil: Getters and Setters Where They're Not Required
We programmers keep our instance variables private and automatically add public setters and getters to them. This is the same as making the instance variables public. Why are we exposing our variables in this way? Getters and Setters allow you to manipulate the internal state of objects from outside of the object. This violates encapsulation. Only the object itself should care about its internal state.
The basic reason for getters and setters in Java is very simple. You can only specify methods, not fields, in an interface. Hence, if you want to allow a field to pass across the interface, you will need a reader and a writer method. These are traditionally called getX and setX for the field x.
But, we should not add automatic getters and setters. Having getters and setters does not in itself break encapsulation. What does break encapsulation is having a getter and a setter for every data member (every field, in java lingo). That is one step away from making all data members public.
The point of encapsulation is not that you should not be able to know or to change the object's internal state from outside the object, but that you should have a reasonable policy for doing it.
Consider an example of a class Person. Let's say a person has a name, a social security number, and an age. Let's say that we do not allow people to ever change their names or social security numbers. However, the person's age should be incremented by 1 every year. In this case, you would provide a constructor that would initialize the name and the SSN to the given values, and which would initialize the age to 0. You would also provide a method incrementAge(), which would increase the age by 1. You would also provide getters for all three. No setters are required in this case.
In this design you allow the state of the object to be inspected from outside the class, and you allow it to be changed from outside the class. However, you do not allow the state to be changed arbitrarily. There is a policy, which effectively states that the name and the SSN cannot be changed at all, and that the age can be incremented by 1 year at a time.
Now let's say a person also has a salary. And people can change jobs at will, which means their salary will also change. To model this situation we have no other way but to provide a setSalary() method! Allowing the salary to be changed at will is a perfectly reasonable policy in this case.
- Very evil: public fields.
- Somewhat evil: Getters and setters where they're not required.
- Good: Getters and setters only where they're really required - make the type expose "larger" behaviour which happens to use its state, rather than just treating the type as a repository of state to be manipulated by other types.