Kotlin Interfaces explained. Interfaces vs Abstract classes
Interfaces are a feature in Kotlin that enables developers to define contracts for classes without enforcing inheritance. By combining abstract methods and default implementations, interfaces provide flexibility and modularity.
In this blog, we’ll explore what interfaces are, how to use them, and how they differ from abstract classes. By the end, you’ll have a solid understanding of when and why to use interfaces in Kotlin.
What is an Interface?
In Kotlin, an interface can contain both declarations of abstract methods (methods without implementation) and methods with implementation. It serves as a blueprint for classes, allowing them to define shared behaviours.
Definition:
An interface in Kotlin can contain declarations of abstract methods and method implementations.
Here’s an example:
interface Vehicle {
fun engine()
}
class Car : Vehicle {
override fun engine() {
println("Engine Starting in Car")
}
}
In this example:
Vehicle
defines a contract that any implementing class must follow.Car
implements theVehicle
interface and provides the implementation for theengine()
method.
Why Use Interfaces?
Interfaces are useful when you need to define shared functionality across unrelated classes. For instance, consider the example below:
interface MaintenanceInterface {
fun needMaintenanceTimePeriod()
}
class Car : MaintenanceInterface {
override fun needMaintenanceTimePeriod() {
println("Maintenance Period - Every 6 months")
}
}class AirConditioner : MaintenanceInterface {
override fun needMaintenanceTimePeriod() {
println("Maintenance Period - Every 1 Year")
}
}
Here:
- Both
Car
andAirConditioner
are unrelated entities, yet they share a common functionality: maintenance. - Using an interface, we define a common contract without forcing inheritance, promoting code reusability and flexibility.
Interface vs. Abstract Classes
Although interfaces and abstract classes may seem similar, they serve different purposes. Abstract classes are designed as a base class for inheritance, while interfaces define contracts or capabilities.
Abstract Class Example:
abstract class Animal(val name: String) {
abstract fun makeSound()
fun eat() {
println("$name is eating.")
}
}
class Dog(name: String) : Animal(name) {
override fun makeSound() {
println("Bark!")
}
}class Cat(name: String) : Animal(name) {
override fun makeSound() {
println("Meow!")
}
}
Key Differences:
Understanding the Limitations of Interfaces
No Backing Fields
In Kotlin, properties in an interface cannot have backing fields. This means you cannot store values directly in an interface.
Example:
interface Vehicle {
var tyres: Int
get() = 4
set(value) {
field = value // ERROR: Interfaces cannot have a backing field
}
}
Advanced Interface Features
Multiple Interface Implementation
Kotlin allows a class to implement multiple interfaces. This is useful when you need a class to support multiple capabilities.
interface A {
fun methodA() {
println("Method A from Interface A")
}
}
interface B {
fun methodB() {
println("Method B from Interface B")
}
}class MyClass : A, Bfun main() {
val obj = MyClass()
obj.methodA()
obj.methodB()
}
Conflict Resolution in Multiple Interfaces
When implementing multiple interfaces with methods of the same name, Kotlin forces you to resolve the conflict by explicitly specifying which implementation to use.
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}class C : A {
override fun bar() { print("bar") }
}class D : A, B {
override fun foo() {
super<A>.foo() // Explicitly call A's implementation
super<B>.foo() // Explicitly call B's implementation
} override fun bar() {
super<B>.bar()
}
}
Best Practices for Using Interfaces:
Follow the Interface Segregation Principle:
Avoid creating large interfaces with too many methods. Instead, split them into smaller, specific interfaces.
Use Interfaces for Capabilities, Not State:
Interfaces define behaviour, while abstract classes define state and behaviour. Use them accordingly.
Ensure Consistency Across Implementations:
All classes implementing an interface must adhere to the contract defined by the interface.
Document Your Interfaces:
Provide clear documentation for what the interface represents and its intended usage.
If you want to understand it in more detail. Here is a video for you:
Conclusion
Interfaces are a cornerstone of Kotlin programming, enabling modularity, flexibility, and reusability. They allow unrelated classes to share common functionality without forcing a rigid inheritance structure. By understanding the nuances of interfaces and their differences from abstract classes, you can write cleaner and more maintainable Kotlin code.