Gabriel said:
How should I correctly declare deprecated an abstract method?
The thing is, that if I left the method abstract, I'm forced to
implement it, so the deprecation does not have any effect.
I would think about this slightly differently.
A method declared abstract is a promise/requirement that concrete subclasses
will provide it.
If you deprecate it, then what you are doing is removing that /promise/ (or
rather, warning people that the promise /will/ be removed later). You are not
telling sub-class implementers that they mustn't implement a method with that
signature, only that you no longer /require/ them to do so. Nothing whatever
prevents, or should, prevent any subclass implementing such a method -- they
can implement whatever methods they want -- but they should be aware that the
method is no longer part of the semantics provided by the abstract class
(considered as a framework).
Take an example. Say we start with a class Animal:
public abstract class Animal
{
public abstract void makeNoise();
public void die()
{
this.makeNoise();
this. lieStrangelyStill();
this.decompose();
}
//...
}
And subclasses Cat and Dog:
public class Cat
extends Animal
{
public void makeNoise() { this.meaow(); }
public void meaow() { /* ... */ }
//...
}
public class Dog
extends Animal
{
public void makeNoise() { this.woof(); }
public void woof() { /* ... */ }
//...
}
The makeNoise() method is used in two ways. One is that users of Animals can
ask them to make a noise without knowing which /kind/ of animal they have. The
other is the (hopefully documented) fact that Animals make a noise as they die.
Now suppose we realise that animals don't all make noises, think Starfish for
instance. So we decide to deprecate the makeNoise() method in Animal. That
may have two different effects since makeNoise() may be used in two different
ways.
Let's take the effect on users of Animals first. Since that method is
deprecated, they can no longer assume that any random Animal can makeNoise().
But that in no way means that Dogs are suddenly silent! /If/ they know that
they are dealing with a Dog then they can ask it to makeNoise(), just the same
as they can ask it to woof(). Similarly they can ask a Cat to makeNoise() or
meaow(). What has vanished is the connection between the two definitions of
makeNoise() -- they have become independent of each other, and are now
connected only by coincidence of name. But they are both still perfectly valid
methods.
So, in that case, you have removed the promise to users of Animals. As you
say, there is a technical problem that subclasses are still (by Java rules)
required to implement it, even though it is (logically) no longer necessary. A
simple solution is to make it concrete (with an empty body) in the superclass;
that will have no effect on subclasses that already implement that method, but
will not constrain new subclasses.
Now consider the effect on sub-class implementers. This is a completely
different issue. The guarantee that die() will call makeNoise() has gone away.
I don't think that's acceptable except in very tightly coupled (and necessarily
small) code-bases. So you can't do that unless you are willing to change all
the subclasses at the same time -- you have to find a different way to change
the framework that won't break client code. (Arguably, part of the problem
here is that die() called a /public/ method which subclasses were expected to
implement -- a rather fragile design).
So it depends on what you are doing with your abstract methods. In one case
you can deprecate them without problems. In the other, you have to find some
way to avoid deprecating it at all.
-- chris