'. '

ProviderAPI

From APIDesign

(Difference between revisions)
Jump to: navigation, search
Line 9: Line 9:
The best construct in [[Java]] to implement [[ProviderAPI]]s is to define these types as [[Java]] '''interface'''s. All their methods are abstract (thus they have to be implemented) and it is clear that changing the interface method signatures renders existing implementation uncompilable.
The best construct in [[Java]] to implement [[ProviderAPI]]s is to define these types as [[Java]] '''interface'''s. All their methods are abstract (thus they have to be implemented) and it is clear that changing the interface method signatures renders existing implementation uncompilable.
-
As soon as a modification of the contract with providers is needed, one should add new interface to be implemented. The the interfaces clearly define version which the provider implemented. One can use '''instanceof''' to check whether the provider implemented old or new version and behave appropriatelly:
+
As soon as a modification of the contract with providers is needed, one should design new interface to be implemented (as described at [[ExtendingInterfaces]] page). The two interfaces clearly define version which the provider implements. One can use '''instanceof''' to check whether the provider implemented old contract only or also the new one. According to result of the ''instanceof''' check, you can switch and behave appropriatelly:
<source lang="java">
<source lang="java">
Line 23: Line 23:
</source>
</source>
-
The list of ''additional'' interface that can be implemented is sometimes hard to find. As the previous code snippet shows, it helps if they are nested interface inside the most general (original) one. When the providers write their implementations, they directly see all available ''extensions'' added in newer revisions of the [[API]].
+
Of course you don't want to spread ''instanceof'' calls all over. But if the ''Playback'' interface is used only inside of ''Player'' class (representing the [[ClientAPI]]), then few additional ''instanceof'' checks don't harm any user of the [[ClinetAPI]] (just its writer, which is always a limited and thus acceptable demage).
 +
 
 +
The list of ''additional'' interfaces that can be implemented is sometimes hard to find. As the previous code snippet shows, it helps if they are nested interface inside the most general (original) one. When the providers write their implementations, they directly see all available ''extensions'' added in newer revisions of the [[API]].
[[Category:APIDesignPatterns]]
[[Category:APIDesignPatterns]]
[[Category:APIDesignPatterns:Evolution]]
[[Category:APIDesignPatterns:Evolution]]

Revision as of 22:52, 19 March 2011

Rules for extending API designed for implementors are very different to those for API that can only be called.

As soon as an implementation of your interface is written, the natural expectation of its author is, that it will work forever.

One can visualize such provider interface as a fixed point - a piece of the [[API] that does not change at all. Well, it can change a bit. You may decide to call its methods more often in new version, or call them less frequently. You may pass in arrays of size 4096 instead of previously used 1024, etc. Slight modifications of the contract are allowed, but compared to ClientAPI (where adding methods is good), the interface for providers is really fixed. No new methods additions (adding a new method would put additional, unsatisfiable requirement on already existing implementors), no refactorings. Stability is good.

The easiest way to break this promise is to add new non-implemented methods into the type. As such do not add new methods to interfaces or abstract classes implemented by some providers. This immediately breaks the promise of BackwardCompatibility.

The best construct in Java to implement ProviderAPIs is to define these types as Java interfaces. All their methods are abstract (thus they have to be implemented) and it is clear that changing the interface method signatures renders existing implementation uncompilable.

As soon as a modification of the contract with providers is needed, one should design new interface to be implemented (as described at ExtendingInterfaces page). The two interfaces clearly define version which the provider implements. One can use instanceof' to check whether the provider implemented old contract only or also the new one. According to result of the instanceof check, you can switch and behave appropriatelly:

/** @since 1.0 */
public interface Playback {
  public void play(byte[] arr);
 
  /** @since 2.0 we can also control volume */
  public interface Volume extends Playback {
    public void setVolume(int volume);
  }
}

Of course you don't want to spread instanceof calls all over. But if the Playback interface is used only inside of Player class (representing the ClientAPI), then few additional instanceof checks don't harm any user of the ClinetAPI (just its writer, which is always a limited and thus acceptable demage).

The list of additional interfaces that can be implemented is sometimes hard to find. As the previous code snippet shows, it helps if they are nested interface inside the most general (original) one. When the providers write their implementations, they directly see all available extensions added in newer revisions of the API.

Personal tools
buy