protected variables allow for multiple entry points. take the case:
public class MyClass {
protected int myProtectedVar;
private int myPrivateVar; // setters and getters omitted, but exist
}
public class Client {
private final MyClass mc = new MyClass();
public void doSomething1() {
mc.myProtectedVar = -1;
mc.setPrivateVar(-1);
}
public void doSomething2() {
mc.myProtectedVar = -2;
mc.setPrivateVar(-2);
}
}
Imagine multiple classes accessing the variables this way. At some point in development, I realized I have a bug where these variables are being set to the incorrect values so now I want to log the sets of the variables.
// easy case for the private variable
public void setPrivateVar(int i) {
LOGGER.debug("Variable i set to " + i);
this.myPrivateVar = i;
}
It should be clear now that the protected variable has no single entry point to log. While this is a trivial example, it can be extended to other concepts, such as validating inputs. It becomes even more of a problem if the variable is say a List. Now the protected variable is exposing the actual list, as opposed to returning an unmodifiable copy of it. Tracing problems gets extremely difficult, very quickly.
Exposing protected variables also discourages the "tell, don't ask" principle. By accessing the variable, you are querying the state of the object presumably to do something based on that state. Rather, you should be telling the object what to do and it will look at its own, private state.
I often hear arguments that it's ok to use protected (or even public) variables for final fields in lightweight data containers (or data transfer objects). I still don't like this because you lose the single entry point to do any sort of action on the data (validation, logging, etc). I generally find that exposing protected variables is a smell that too much internal state is being exposed.
No comments:
Post a Comment