'. '

InvisibleAbstractMethod

From APIDesign

(Difference between revisions)
Jump to: navigation, search
Line 1: Line 1:
-
Having an '''abstract''' class with package private ''abstract'' method effectively prevents anyone to subclass it. That can be considered as [[good]] [[:APIDesignPatterns|API design pattern]], especially if that is something one starts with.
+
Having an '''abstract''' class with package private ''abstract'' method 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 longer.
+
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.
-
The hidden catch is that tools like [[Sigtest]] are unlikely to catch this situation, as they don't care about package private methods! Some people complained about unnecesary complexity of various [[OOP]] access modifiers - and they were likely right, but this case worse (from the point of an [[API]] designer) - a change to an implementation detail may change the published [[API]]s!
+
If the original version of a class contains one abstract method:
-
[[TBD]]
+
<source lang="java">
 +
package api;
 +
/** version 1.0 */
 +
public abstract class AbstractClass {
 +
public abstract void subclassMeAndImplementMe();
 +
}
 +
</source>
 +
 
 +
and later somebody adds a new ''implementation detail'':
 +
 
 +
<source lang="java">
 +
package api;
 +
/** version 2.0 */
 +
public abstract class AbstractClass {
 +
public abstract void subclassMeAndImplementMe();
 +
// hidden, not public new method
 +
abstract void youWillNeverImplementMe();
 +
}
 +
</source>
 +
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:
 +
 
 +
<source lang="bash">
 +
Warning: public class api.AbstractClass can't be extended because contains the following member: method abstract void api.AbstractClass.youWillNeverImplementMe()
 +
</source>
 +
 
 +
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:
 +
 
 +
<source lang="bash">
 +
Class api.AbstractClass:
 +
"E5.2 - Adding abstract methods" : method public abstract void api.AbstractClass.youWillNeverImplementMe()
 +
</source>
 +
 
 +
 
 +
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) - a change to an implementation detail may change the published [[API]]s!
[[Category:APIDesignPatterns:Evolution]]
[[Category:APIDesignPatterns:Evolution]]
[[Category:APIDesignPatterns:Anti]]
[[Category:APIDesignPatterns:Anti]]

Revision as of 12:06, 20 March 2012

Having an abstract class with package private abstract method 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 can't 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) - a change to an implementation detail may change the published APIs!

Personal tools
buy