We have several empty abstract class in our codebase. I find that ugly. But besides this very stupid reason (ugliness), should I refactor it (into empty interface e.g.) ?
The question to ask is: "What do I want to do with this code that I can't do, or find hard to do, because these empty abstract classes are there?" If the answer is 'nothing', you should leave them alone. If the answer is "something", it may well be worthwhile to remove them - but if you can, speak to the people who created them first, just to make sure there isn't some subtle purpose to them. For example, perhaps your code uses reflection to find all instances of a particular ABC and do special things to them, in which case your refactoring could break the code in subtle ways.
According to object oriented programming theory the main purpose for inheritance is polymorphism, code reuse and encapsulation. An empty abstract class (and when i say this i mean truly empty, no constructors, no methods, no properties. nothing!) does not achieve any of the three goals hoped by this programming technique. It is the equivalent to
if(true){...}
. changing it to an interface does not really makes it any better.
If you want to refactor the code i would advise you to think in the direction opposite to the one you are thinking, what i mean by this is: try to abstract properties, methods and constructors from all classes that share a abstract parent class.
This is hard work with little reward in the short term but it increases the maintainability of the code dramatically since a core logic change would have to be done only once. I suspect the reason for using those empty abstract classes is to identify a group of classes that must share something in common otherwise what would be the difference between Object
and the abstract class
If you have the following pattern you will find it to be the most flexible:
interface Fooable
{
void foo();
void bar();
}
abstract class AbstractFoo
implements Fooable
{
}
class Foo
extends AbstractFoo
{
public void foo()
{
}
public void bar()
{
}
}
This way you can always pass by the interface but if you later find that you have code that can be common you can put it in the abstract class without having to make changes to all of the classes.
Unless you have a good reason for not doing that pattern (and I suspect you don't in this case) I would suggest using it. This can wind up with empty abstract classes but I think it is ok (a little odd, but ok).
If there truly are no methods in the interface or only one then I would skip the abstract class.
From a compiler/functional point of view there is no real difference between an interface and an abstract class where all method are abstract. The interface will be more flexible than the abstract class, and the interface + abstract class will be the most flexible of all.
If it were my code I'd make the change to them being interfaces...
It is not necessarily more ugly than the alternative, which may be repeating code.
In an ideal world you would be able to model using only interfaces. for example: Vehicel -> Car -> Pontiac.
But there may be logic which is the same for all Vehicels, so an interface is not appropriate. And you don't have logic specific to Cars. But you do want a Car abstraction because your TrafficLightController wants to distinguish between Cars and Bicycles.
In that case you need to make and abstract Car.
Or you can make an interface Vehicle, a VehicleImpl implements Vehicle, an interface Car extends Vehicle, an interface Pontiac implements Car, and a PontiacImpl implements Pontiac extends VehicleImpl. I personally dislike a parallel hierarchy of interfaces for the sake of preventing an empty abstract class more than an empty abstract class.
So I guess it's a matter of taste.
One caveat; if you use a lot of proxied classes like with Spring and some testing frameworks a parallel interface hierarchy might well result in less unexpected errors.
While I don't get what will be in the table that the empty class is mapped to, if the class serves some purpose, well, keep it, until you have an opportunity to refactor some.
What I would definitely do is: write a comment about why this class exists in the file. One big reason for clean and "beautiful" code is to not make other developers think. A comment can help with that, even if the code is not as pretty as it could be.