This answer does a good job of explaining the differences between an abstract class and an interface, but it doesn't answer why you should declare one.
From a purely technical standpoint, there is never a requirement to declare a class as abstract.
Consider the following three classes:
class Database {
public String[] getTableNames() { return null; } //or throw an exception? who knows...
}
class SqlDatabase extends Database { } //TODO: override getTableNames
class OracleDatabase extends Database { } //TODO: override getTableNames
You don't have to make the Database class abstract, even though there is an obvious problem with its implementation: When you are writing this program, you could type new Database()
and it would be valid, but it would never work.
Regardless, you would still get polymorphism, so as long as your program only makes SqlDatabase
and OracleDatabase
instances, you could write methods like:
public void printTableNames(Database database) {
String[] names = database.getTableNames();
}
Abstract classes improve the situation by preventing a developer from instantiating the base class, because a developer has marked it as having missing functionality. It also provides compile-time safety so that you can ensure that any classes that extend your abstract class provide the bare minimum functionality to work, and you don't need to worry about putting stub methods (like the one above) that inheritors somehow have to magically know that they have to override a method in order to make it work.
Interfaces are a totally separate topic. An interface lets you describe what operations can be performed on an object. You would typically use interfaces when writing methods, components, etc. that use the services of other components, objects, but you don't care what the actual type of object you are getting the services from is.
Consider the following method:
public void saveToDatabase(IProductDatabase database) {
database.addProduct(this.getName(), this.getPrice());
}
You don't care about whether the database
object inherits from any particular object, you just care that it has an addProduct
method. So in this case, an interface is better suited than making all of your classes happen to inherit from the same base class.
Sometimes the combination of the two works very nicely. For example:
abstract class RemoteDatabase implements IProductDatabase {
public abstract String[] connect();
public abstract void writeRow(string col1, string col2);
public void addProduct(String name, Double price) {
connect();
writeRow(name, price.toString());
}
}
class SqlDatabase extends RemoteDatabase {
//TODO override connect and writeRow
}
class OracleDatabase extends RemoteDatabase {
//TODO override connect and writeRow
}
class FileDatabase implements IProductDatabase {
public void addProduct(String name, Double price) {
//TODO: just write to file
}
}
Notice how some of the databases inherit from RemoteDatabase to share some functionality (like connecting before writing a row), but FileDatabase is separate class that only implements IProductDatabase
.