Which Do You Use?
On the surface, it seems like interfaces can do nearly everything that abstract classes can do, and you gain the flexibility of being able to use more than one interface on a class.
So, why would one ever use an abstract class? Or, to put it another way, in what scenarios would you use abstract classes, and in what scenarios would you use interfaces?
State Management
The biggest thing that interfaces lack is any form of state management. They cannot have concrete properties, the way abstract classes (and regular classes) can.
So, if you want to have something that manages state but requires implementations to fulfill some contract, an abstract class is the better choice.
In principle, you could use interfaces and simply force implementations to do some of the state management themselves. For example, you could have abstract getFoo()
and setFoo()
functions declared in the interface, plus have concrete code in the interface rely upon those functions. In principle, this can work. However, the interface has no control over exactly how that state is maintained:
- Is it one “foo” per instance of the class?
- Is it one “foo” per process (e.g., a top-level
var
)? - Is it one “foo” per some sort of context (e.g., per user in a Web app)?
If the interface truly does not care and could handle any of those scenarios, fine. Otherwise, an abstract class would be a better choice, so the concrete code knows exactly how the state management is being handled.
On the other hand, if you have some code that is more of a “mixin” and does not need any particular state, then interfaces are fine.
Consumer of Contracts
Another subtle limitation is that interfaces cannot have protected
functions. The abstract
functions on an interface are intrinsically public, though their concrete functions can be private
if desired.
Hence, if you want to require subclasses to implement some functionality, but that functionality should not be accessible to arbitrary other objects, an abstract class with protected abstract
functions is the best choice.
If, on the other hand, all of the abstract
functions are fine for other objects to call, then interfaces are fine.
I Can Haz final
?
Interfaces can inherit from other interfaces, using the same notation as one uses to inherit with classes:
interface Base {
fun foo()
}
interface Sub : Base {
fun bar()
fun goo() {
// do something
}
}
However, an interface cannot mark an inherited abstract
method as final
, even if it provides an implementation. So, this is fine:
interface Base {
fun foo()
}
interface Sub : Base {
fun bar()
fun goo() {
// do something
}
override fun foo() {
// this supplies an implementation
}
}
…but this is not:
interface Base {
fun foo()
}
interface Sub : Base {
fun bar()
fun goo() {
// do something
}
override final fun foo() {
// this supplies an implementation
}
}
Instead, we get a compile error:
error: modifier 'final' is not applicable inside 'interface'
override final fun foo() {
^
Abstract classes, like regular classes, can override inherited methods and declare those overridden methods as final
, to prevent further subclasses from overriding them.
As a result, anything in an interface hierarchy is permanently open
, until you start implementing the interfaces in classes. If that is a problem — if you have some function that you really want to mark as final
— use abstract classes, not interfaces.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.