ClarityOfTypes
From APIDesign
The fuzziness is all around us, including our APIs. The essay ClarityOfAccessModifiers explains the importance correct choice of access modifiers. The EliminateFuzzyModifiers gives a recipe how to turn those fuzzy meanings into clear ones. Yet the result is still not ideal. Something is missing.
This essay en-light what is it. More on the topic can be found in Chapter 10 of TheAPIBook. Here is a shorter version.
The final result of elimination of public, protected and public abstract can be triplication of each fuzzy method. This may not be bad in all times, for example CharsetDecoder successfully provides duplicated version of methods (one for ClientAPI users and one for providers subclassing the class), but on the other hand this is definitely distracting. Here is an example of correct, but complex elimination:
Code from Arithmetica.java:
See the whole file.public final int sumTwo(int one, int second) { return overridableSumTwo(one, second); } protected abstract int overridableSumTwo(int one, int second); protected final int defaultSumTwo(int one, int second) { return one + second; }
Callers to the API reading Javadoc see all the methods and in fact only half of them is of some interest. They need to ignore the rest. It would be much better to separate the concerns and have one API for callers and one for implementors.
This can be achieved by using DelegationAndComposition. Create one type for client API users, another type for implementors and yet another to hold methods used for callback from providers to the superclass implementation (callback means protected final as mentioned here).
Theory
Imagine we have a class full of clear, single meaning access modifiers. However, as we understand now, we want to separate them into individual types each targeted to appropriate audience:
Code from MixedClass.java:
See the whole file.public abstract class MixedClass { private int counter; private int sum; protected MixedClass() { super(); } public final int apiForClients() { int subclass = toBeImplementedBySubclass(); sum += subclass; return sum / counter; } protected abstract int toBeImplementedBySubclass(); protected final void toBeCalledBySubclass() { counter++; } }
Then the possible rewrite using DelegationAndComposition is to introduce one class for ClientAPI users, one interface for subclassers:
Code from NonMixed.java:
See the whole file.public final class NonMixed { int counter; private int sum; private final Provider impl; NonMixed(Provider impl) { this.impl = impl; } public final int apiForClients() { int subclass = impl.toBeImplementedBySubclass(); sum += subclass; return sum / counter; } }
The ClientAPI class if final and as such all its methods are public final' which is single meaning access modifier.
TBD.
<comments/>