InvisibleAbstractMethod
From APIDesign
(2 intermediate revisions not shown.) | |||
Line 1: | Line 1: | ||
- | Having | + | Having a package private [[InvisibleAbstractMethod|invisible abstract method]] in an [[abstract class]] effectively prevents anyone using such [[API]] to subclass it. This can be considered as [[good]] [[:APIDesignPatterns|API design pattern]], especially if such pattern is used since initial version of the [[API]]. |
However it can also turn into a huge anti-pattern. Adding first package private ''abstract'' method into an abstract class is in fact an incompatible change. If the class used to be subclassable before, this prevents the subclassing and as such classes that used to compile may compile no more. | However it can also turn into a huge anti-pattern. Adding first package private ''abstract'' method into an abstract class is in fact an incompatible change. If the class used to be subclassable before, this prevents the subclassing and as such classes that used to compile may compile no more. |
Current revision
Having a package private invisible abstract method in an abstract class effectively prevents anyone using such API to subclass it. This can be considered as good API design pattern, especially if such pattern is used since initial version of the API.
However it can also turn into a huge anti-pattern. Adding first package private abstract method into an abstract class is in fact an incompatible change. If the class used to be subclassable before, this prevents the subclassing and as such classes that used to compile may compile no more.
If the original version of a class contains one abstract method:
package api; /** version 1.0 */ public abstract class AbstractClass { public abstract void subclassMeAndImplementMe(); }
and later somebody adds a new implementation detail:
package api; /** version 2.0 */ public abstract class AbstractClass { public abstract void subclassMeAndImplementMe(); // hidden, not public new method abstract void youWillNeverImplementMe(); }
then we are facing an incompatible change. Inspite of not changing the visible methods of the class at all!
The hidden catch is that tools like Sigtest are unlikely to catch this situation, as they don't care about package private methods! Sigtest only emits a warning:
Warning: public class api.AbstractClass cannot be extended because contains the following member: method abstract void api.AbstractClass.youWillNeverImplementMe()
However warning is not enough, this is an incompatible change and it should be reported as such. The error should be same as in case somebody makes the youWillNeverImplementMe method public abstract. In such situation sigtest properly reports error:
Class api.AbstractClass: "E5.2 - Adding abstract methods" : method public abstract void api.AbstractClass.youWillNeverImplementMe()
Some people complained about unnecessary complexity of various OOP access modifiers - and they were likely right, but this case is worse (from the point of an API designer). So far API authors needed to care only about public and protected elements (as described for example in ClarityOfAccessModifiers), but it seems that we need to paly attention also to non-visible ones - a change to an implementation detail may change the published APIs!