←Older revision |
Revision as of 12:06, 20 March 2012 |
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]] |