'. '

ClarityOfTypes

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(Theory)
Line 26: Line 26:
There is also the ''Callback'' class which holds originally '''protected final''' methods. It is a final class, with non-public constructor, so its creation is fully under the control of the ''NonMixed'' [[API]] infrastructure. Clients of the ''NonMixed'' class cannot get access to it - the reference is only available to the ''Provider'' interface via the ''initialize'' method. As such its use is ''protected'', only ''Provider'' interface implementor can call its methods. Moreover the class is final and as such its methods have only single meaning: ''call me, if you are implementing the provider''. Fully [[Clarity|clear]] again.
There is also the ''Callback'' class which holds originally '''protected final''' methods. It is a final class, with non-public constructor, so its creation is fully under the control of the ''NonMixed'' [[API]] infrastructure. Clients of the ''NonMixed'' class cannot get access to it - the reference is only available to the ''Provider'' interface via the ''initialize'' method. As such its use is ''protected'', only ''Provider'' interface implementor can call its methods. Moreover the class is final and as such its methods have only single meaning: ''call me, if you are implementing the provider''. Fully [[Clarity|clear]] again.
 +
 +
=== [[Clarity]] for [[ClientAPI|Clients]] ===
 +
 +
Clients that hold reference to ''NonMixed'' class see only its '''public''' methods in [[Javadoc]], IDE code completion, etc. They are not distracted by details useful only for providers (except the ''create'' factory method, but that one could be moved to other class, it does not have to be in ''NonMixed'' one as in this example). The code that [[ClientAPI|callers]] need to provide is completely the same as in the original ''Mixed'' class - e.g. we achieved [[clarity]] for [[ClientAPI|callers]] without complicating their code even a bit!
 +
 +
=== [[Clarity]] for [[ProviderAPI|Implementors]] ===
 +
 +
The use case for [[ProviderAPI|implementors]] is slightly changed, but not dramatically.
TBD.
TBD.
<comments/>
<comments/>
 +
 +
 +
[[Category:APIDesignPattern:Clarity]]

Revision as of 08:14, 1 April 2009

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 NonMixed is final and as such all its methods are public final which is single meaning access modifier.

The originally protected abstract methods are moved to Provider interface. Interface methods are public and this might seem like a contradiction to ClarityOfAccessModifiers. However, it is not. The instances of Provider interface are not accessible to clients of the API. They are hidden and only useful for the create factory method that turns them into NonMixed instances. As such they are single meaning methods with only one message: implement me, don't call me!. And the clarity is kept.

There is also the Callback class which holds originally protected final methods. It is a final class, with non-public constructor, so its creation is fully under the control of the NonMixed API infrastructure. Clients of the NonMixed class cannot get access to it - the reference is only available to the Provider interface via the initialize method. As such its use is protected, only Provider interface implementor can call its methods. Moreover the class is final and as such its methods have only single meaning: call me, if you are implementing the provider. Fully clear again.

Clarity for Clients

Clients that hold reference to NonMixed class see only its public methods in Javadoc, IDE code completion, etc. They are not distracted by details useful only for providers (except the create factory method, but that one could be moved to other class, it does not have to be in NonMixed one as in this example). The code that callers need to provide is completely the same as in the original Mixed class - e.g. we achieved clarity for callers without complicating their code even a bit!

Clarity for Implementors

The use case for implementors is slightly changed, but not dramatically.

TBD.

<comments/>

Personal tools
buy