Kotlin Interfaces

A Kotlin interface is a blueprint that defines a set of methods and properties that implementing classes must provide. Unlike abstract classes, interfaces in Kotlin can contain both abstract declarations and concrete implementations with default behavior. The interface keyword is used to declare interfaces in Kotlin, making them a cornerstone of object-oriented design patterns.

interface VehicleInterface {  
    val maxSpeed: Int  
    fun start()  
    fun stop() {  
        println("Vehicle stopped safely")  
    }  
}  

Kotlin Interface Declaration Syntax

Creating Kotlin interface declarations follows a straightforward syntax pattern. You begin with the interface keyword, followed by the interface name, and then define the contract within curly braces.

Basic Interface Structure

interface MobileDevice {  
    // Abstract property - must be implemented  
    val screenSize: Double  
      
    // Abstract method - must be implemented    
    fun powerOn()  
      
    // Method with default implementation  
    fun displayInfo() {  
        println("Mobile device with $screenSize inch screen")  
    }  
}  

Interface Properties in Kotlin

Kotlin interface properties can be abstract or have custom getter implementations. Unlike Java interfaces, Kotlin interfaces can declare properties, but they cannot store state directly.

interface StorageDevice {  
    // Abstract property  
    val capacity: Int  
      
    // Property with custom getter  
    val formattedCapacity: String  
        get() = "${capacity}GB"  
      
    // Property with backing field - NOT ALLOWED  
    // val serialNumber: String = "12345" // Compilation error  
}  

Kotlin Interface Implementation

Implementing Kotlin interfaces requires using the colon (:) operator followed by the interface name. All abstract members must be overridden using the override keyword.

Single Interface Implementation

interface AudioPlayer {  
    val supportedFormats: List<String>  
    fun play(file: String)  
    fun pause()  
    fun getVolume(): Int = 50 // Default implementation  
}  
  
class MusicPlayer : AudioPlayer {  
    override val supportedFormats = listOf("MP3", "WAV", "FLAC")  
      
    override fun play(file: String) {  
        println("Playing $file")  
    }  
      
    override fun pause() {  
        println("Playback paused")  
    }  
      
    // Optional: override default implementation  
    override fun getVolume(): Int = 75  
}  

Kotlin Multiple Interface Implementation

One of the most powerful features is Kotlin multiple interface implementation, allowing a single class to implement several interfaces simultaneously.

interface Drawable {  
    fun draw()  
    fun getColor(): String = "black"  
}  
  
interface Clickable {  
    fun onClick()  
    fun isEnabled(): Boolean = true  
}  
  
class Button : Drawable, Clickable {  
    override fun draw() {  
        println("Drawing button with color: ${getColor()}")  
    }  
      
    override fun onClick() {  
        if (isEnabled()) {  
            println("Button clicked!")  
        }  
    }  
}  

Resolving Conflicting Interface Methods

When implementing multiple Kotlin interfaces with conflicting method signatures, you must explicitly resolve the conflicts:

interface NetworkInterface {  
    fun connect() {  
        println("Network connection established")  
    }  
}  
  
interface BluetoothInterface {  
    fun connect() {  
        println("Bluetooth paired successfully")  
    }  
}  
  
class SmartPhone : NetworkInterface, BluetoothInterface {  
    override fun connect() {  
        // Call specific interface methods  
        super<NetworkInterface>.connect()  
        super<BluetoothInterface>.connect()  
        println("All connections ready")  
    }  
}  

Kotlin Interface vs Abstract Class

Understanding the difference between Kotlin interfaces vs abstract classes helps choose the right abstraction level:

FeatureInterfaceAbstract Class
Multiple inheritance✅ Supported❌ Single inheritance only
State storage❌ No backing fields✅ Can store state
Constructor❌ No constructors✅ Can have constructors
Property initialization❌ Cannot initialize✅ Can initialize properties
// Interface - contract definition  
interface PaymentProcessor {  
    val processorName: String  
    fun processPayment(amount: Double): Boolean  
}  
  
// Abstract class - partial implementation  
abstract class BasePaymentProcessor {  
    protected var transactionCount = 0 // State storage  
      
    abstract fun validatePayment(amount: Double): Boolean  
      
    fun logTransaction() { // Concrete implementation  
        transactionCount++  
        println("Transaction #$transactionCount processed")  
    }  
}  

Kotlin Interface Default Methods

Kotlin interface default methods provide implementations that can be optionally overridden by implementing classes:

interface NotificationSender {  
    fun sendNotification(message: String, recipient: String)  
      
    // Default method with implementation  
    fun formatMessage(message: String): String {  
        return "[${getCurrentTime()}] $message"  
    }  
      
    // Default method calling abstract method  
    fun sendFormattedNotification(message: String, recipient: String) {  
        sendNotification(formatMessage(message), recipient)  
    }  
      
    private fun getCurrentTime(): String = "2025-01-20 10:30:00"  
}  
  
class EmailSender : NotificationSender {  
    override fun sendNotification(message: String, recipient: String) {  
        println("Email sent to $recipient: $message")  
    }  
      
    // Optionally override default implementation  
    override fun formatMessage(message: String): String {  
        return "📧 EMAIL: $message"  
    }  
}  

Advanced Kotlin Interface Patterns

Functional Interfaces (SAM Interfaces)

Kotlin functional interfaces contain exactly one abstract method and can be used with lambda expressions:

fun interface ClickListener {  
    fun onClick(view: String)  
}  
  
class ButtonWidget {  
    private var listener: ClickListener? = null  
      
    fun setOnClickListener(listener: ClickListener) {  
        this.listener = listener  
    }  
      
    fun performClick() {  
        listener?.onClick("Button")  
    }  
}  
  
// Usage with lambda  
val button = ButtonWidget()  
button.setOnClickListener { view ->   
    println("$view was clicked!")  
}  

Interface Delegation

Kotlin interface delegation allows delegating interface implementation to another object:

interface Logger {  
    fun log(message: String)  
}  
  
class FileLogger : Logger {  
    override fun log(message: String) {  
        println("Writing to file: $message")  
    }  
}  
  
class DatabaseManager(logger: Logger) : Logger by logger {  
    fun saveUser(name: String) {  
        log("Saving user: $name")  
        // Database save logic here  
    }  
}  
  
// Usage  
val fileLogger = FileLogger()  
val dbManager = DatabaseManager(fileLogger)  
dbManager.saveUser("John Doe") // Uses delegated logger  

Real-World Kotlin Interface Examples

Repository Pattern Implementation

interface UserRepository {  
    suspend fun getUserById(id: String): User?  
    suspend fun saveUser(user: User): Boolean  
    suspend fun deleteUser(id: String): Boolean  
      
    // Default caching behavior  
    fun getCacheKey(id: String): String = "user_$id"  
}  
  
class RemoteUserRepository : UserRepository {  
    override suspend fun getUserById(id: String): User? {  
        // API call implementation  
        println("Fetching user $id from remote server")  
        return User(id, "John Doe", "john@example.com")  
    }  
      
    override suspend fun saveUser(user: User): Boolean {  
        println("Saving user ${user.name} to remote server")  
        return true  
    }  
      
    override suspend fun deleteUser(id: String): Boolean {  
        println("Deleting user $id from remote server")  
        return true  
    }  
}  
  
class LocalUserRepository : UserRepository {  
    private val users = mutableMapOf<String, User>()  
      
    override suspend fun getUserById(id: String): User? {  
        return users[id]  
    }  
      
    override suspend fun saveUser(user: User): Boolean {  
        users[user.id] = user  
        println("User ${user.name} saved locally")  
        return true  
    }  
      
    override suspend fun deleteUser(id: String): Boolean {  
        return users.remove(id) != null  
    }  
}  
  
data class User(val id: String, val name: String, val email: String)  

Event Handling System

interface EventListener<T> {  
    fun onEvent(event: T)  
    fun canHandle(event: T): Boolean = true  
}  
  
interface EventDispatcher<T> {  
    fun addEventListener(listener: EventListener<T>)  
    fun removeEventListener(listener: EventListener<T>)  
    fun dispatch(event: T)  
}  
  
class SimpleEventDispatcher<T> : EventDispatcher<T> {  
    private val listeners = mutableListOf<EventListener<T>>()  
      
    override fun addEventListener(listener: EventListener<T>) {  
        listeners.add(listener)  
    }  
      
    override fun removeEventListener(listener: EventListener<T>) {  
        listeners.remove(listener)  
    }  
      
    override fun dispatch(event: T) {  
        listeners.filter { it.canHandle(event) }  
                 .forEach { it.onEvent(event) }  
    }  
}  
  
// Usage example  
sealed class UserEvent {  
    data class UserLoggedIn(val userId: String) : UserEvent()  
    data class UserLoggedOut(val userId: String) : UserEvent()  
}  
  
class AnalyticsListener : EventListener<UserEvent> {  
    override fun onEvent(event: UserEvent) {  
        when (event) {  
            is UserEvent.UserLoggedIn ->   
                println("Analytics: User ${event.userId} logged in")  
            is UserEvent.UserLoggedOut ->   
                println("Analytics: User ${event.userId} logged out")  
        }  
    }  
}  

Complete Working Example

Here’s a comprehensive example demonstrating Kotlin interfaces in a mobile app context:

import kotlinx.coroutines.*  
  
// Data models  
data class Product(val id: String, val name: String, val price: Double)  
data class CartItem(val product: Product, var quantity: Int)  
  
// Core interfaces  
interface ProductService {  
    suspend fun getProducts(): List<Product>  
    suspend fun getProductById(id: String): Product?  
}  
  
interface CartService {  
    fun addItem(product: Product, quantity: Int = 1)  
    fun removeItem(productId: String)  
    fun getItems(): List<CartItem>  
    fun getTotalPrice(): Double  
    fun clear()  
}  
  
interface PaymentProcessor {  
    suspend fun processPayment(amount: Double): PaymentResult  
    fun getSupportedMethods(): List<String>  
}  
  
// Payment result  
sealed class PaymentResult {  
    object Success : PaymentResult()  
    data class Failed(val reason: String) : PaymentResult()  
}  
  
// Implementations  
class MockProductService : ProductService {  
    private val products = listOf(  
        Product("1", "Smartphone", 699.99),  
        Product("2", "Laptop", 1299.99),  
        Product("3", "Headphones", 199.99)  
    )  
      
    override suspend fun getProducts(): List<Product> {  
        delay(500) // Simulate network delay  
        return products  
    }  
      
    override suspend fun getProductById(id: String): Product? {  
        delay(200)  
        return products.find { it.id == id }  
    }  
}  
  
class InMemoryCartService : CartService {  
    private val items = mutableListOf<CartItem>()  
      
    override fun addItem(product: Product, quantity: Int) {  
        val existingItem = items.find { it.product.id == product.id }  
        if (existingItem != null) {  
            existingItem.quantity += quantity  
        } else {  
            items.add(CartItem(product, quantity))  
        }  
        println("Added ${product.name} x$quantity to cart")  
    }  
      
    override fun removeItem(productId: String) {  
        items.removeAll { it.product.id == productId }  
        println("Removed product $productId from cart")  
    }  
      
    override fun getItems(): List<CartItem> = items.toList()  
      
    override fun getTotalPrice(): Double {  
        return items.sumOf { it.product.price * it.quantity }  
    }  
      
    override fun clear() {  
        items.clear()  
        println("Cart cleared")  
    }  
}  
  
class CreditCardProcessor : PaymentProcessor {  
    override suspend fun processPayment(amount: Double): PaymentResult {  
        delay(1000) // Simulate payment processing  
        return if (amount > 0) {  
            println("Payment of $${"%.2f".format(amount)} processed successfully")  
            PaymentResult.Success  
        } else {  
            PaymentResult.Failed("Invalid amount")  
        }  
    }  
      
    override fun getSupportedMethods(): List<String> {  
        return listOf("Visa", "MasterCard", "American Express")  
    }  
}  
  
// Shopping application using interfaces  
class ShoppingApp(  
    private val productService: ProductService,  
    private val cartService: CartService,  
    private val paymentProcessor: PaymentProcessor  
) {  
    suspend fun displayProducts() {  
        println("\n=== Available Products ===")  
        val products = productService.getProducts()  
        products.forEach { product ->  
            println("${product.id}. ${product.name} - $${product.price}")  
        }  
    }  
      
    suspend fun addToCart(productId: String, quantity: Int = 1) {  
        val product = productService.getProductById(productId)  
        if (product != null) {  
            cartService.addItem(product, quantity)  
        } else {  
            println("Product not found")  
        }  
    }  
      
    fun displayCart() {  
        println("\n=== Shopping Cart ===")  
        val items = cartService.getItems()  
        if (items.isEmpty()) {  
            println("Cart is empty")  
        } else {  
            items.forEach { item ->  
                val total = item.product.price * item.quantity  
                println("${item.product.name} x${item.quantity} = $${"%.2f".format(total)}")  
            }  
            println("Total: $${"%.2f".format(cartService.getTotalPrice())}")  
        }  
    }  
      
    suspend fun checkout() {  
        val total = cartService.getTotalPrice()  
        if (total > 0) {  
            println("\n=== Processing Checkout ===")  
            println("Payment methods: ${paymentProcessor.getSupportedMethods().joinToString(", ")}")  
              
            when (val result = paymentProcessor.processPayment(total)) {  
                is PaymentResult.Success -> {  
                    println("Order completed successfully!")  
                    cartService.clear()  
                }  
                is PaymentResult.Failed -> {  
                    println("Payment failed: ${result.reason}")  
                }  
            }  
        } else {  
            println("Cart is empty, nothing to checkout")  
        }  
    }  
}  
  
// Main function demonstrating the application  
suspend fun main() {  
    // Initialize services  
    val productService = MockProductService()  
    val cartService = InMemoryCartService()  
    val paymentProcessor = CreditCardProcessor()  
      
    // Create shopping app  
    val app = ShoppingApp(productService, cartService, paymentProcessor)  
      
    // Demo workflow  
    app.displayProducts()  
      
    // Add items to cart  
    app.addToCart("1", 2) // 2 smartphones  
    app.addToCart("3", 1) // 1 headphones  
      
    // Display cart  
    app.displayCart()  
      
    // Process checkout  
    app.checkout()  
      
    // Display final cart state  
    app.displayCart()  
}  

Expected Output:

=== Available Products ===  
1. Smartphone - $699.99  
2. Laptop - $1299.99  
3. Headphones - $199.99  
  
Added Smartphone x2 to cart  
Added Headphones x1 to cart  
  
=== Shopping Cart ===  
Smartphone x2 = $1399.98  
Headphones x1 = $199.99  
Total: $1599.97  
  
=== Processing Checkout ===  
Payment methods: Visa, MasterCard, American Express  
Payment of $1599.97 processed successfully  
Order completed successfully!  
Cart cleared  
  
=== Shopping Cart ===  
Cart is empty  

This comprehensive example demonstrates how Kotlin interfaces enable clean architecture, dependency injection, and testable code. The interfaces define clear contracts while implementations provide specific behavior, making the system flexible and maintainable for real-world applications.