Interface trong Kotlin
🎯 Mục tiêu: Hiểu Interface - contract định nghĩa hành vi chung, với default implementations, properties, và cách resolve conflicts.
💡 Interface là gì?
Interface định nghĩa “contract” - tập hợp các methods và properties mà class phải có. Nó mô tả “cái gì” (what) mà không quan tâm “như thế nào” (how).
// Định nghĩa interface
interface Clickable {
fun click()
}
// Class implement interface
class Button : Clickable {
override fun click() {
println("Button clicked!")
}
}
fun main() {
val button = Button()
button.click() // Button clicked!
// Polymorphism - lưu Button như Clickable
val clickable: Clickable = button
clickable.click() // Button clicked!
}📝 Tại sao cần Interface?
Polymorphism - Đa hình
interface Playable {
fun play()
}
class MusicPlayer : Playable {
override fun play() = println("🎵 Playing music...")
}
class VideoPlayer : Playable {
override fun play() = println("🎬 Playing video...")
}
class Game : Playable {
override fun play() = println("🎮 Playing game...")
}
// Hàm làm việc với bất kỳ Playable nào
fun startMedia(media: Playable) {
print("Starting: ")
media.play()
}
fun main() {
startMedia(MusicPlayer()) // Starting: 🎵 Playing music...
startMedia(VideoPlayer()) // Starting: 🎬 Playing video...
startMedia(Game()) // Starting: 🎮 Playing game...
}Loose Coupling - Giảm phụ thuộc
// Bad: Tight coupling
class EmailService {
fun sendEmail(message: String) { /* ... */ }
}
class OrderProcessor {
private val emailService = EmailService() // ❌ Phụ thuộc trực tiếp
fun processOrder(order: Order) {
emailService.sendEmail("Order confirmed")
}
}
// Good: Loose coupling với Interface
interface NotificationService {
fun notify(message: String)
}
class EmailNotification : NotificationService {
override fun notify(message: String) = println("Email: $message")
}
class SMSNotification : NotificationService {
override fun notify(message: String) = println("SMS: $message")
}
class OrderProcessor(private val notifier: NotificationService) {
fun processOrder(order: Order) {
// Logic...
notifier.notify("Order confirmed")
}
}
fun main() {
// Dễ dàng switch implementation
val emailProcessor = OrderProcessor(EmailNotification())
val smsProcessor = OrderProcessor(SMSNotification())
}🔧 Default Implementation
Interface có thể có default implementation - không bắt buộc override:
interface Clickable {
fun click() // Abstract - PHẢI implement
fun showOff() = println("I'm clickable!") // Default - optional override
fun doubleClick() { // Cũng là default implementation
click()
click()
}
}
class Button(val name: String) : Clickable {
override fun click() {
println("$name clicked")
}
// showOff() và doubleClick() đã có default, không cần override
}
fun main() {
val button = Button("Submit")
button.click() // Submit clicked
button.showOff() // I'm clickable!
button.doubleClick() // Submit clicked \n Submit clicked
}Khác với Java < 8: Java 8+ mới có default methods. Kotlin hỗ trợ từ đầu.
📦 Interface Properties
Interface có thể có abstract properties:
interface Identifiable {
val id: String // Abstract property
val createdAt: Long // Abstract property
// Property với default getter
val displayId: String
get() = "ID: $id"
}
class User(override val id: String) : Identifiable {
override val createdAt = System.currentTimeMillis()
}
class Document(override val id: String) : Identifiable {
override val createdAt = System.currentTimeMillis()
}
fun main() {
val user = User("user-123")
println(user.displayId) // ID: user-123
println(user.createdAt) // Timestamp
}Interface KHÔNG có backing field: Không thể khởi tạo state trong interface.
interface Bad {
val name: String = "Default" // ❌ Lỗi! Không có backing field
}
interface Good {
val name: String // ✅ Abstract
get() = "Default" // ✅ Default getter (computed, không lưu state)
}🔀 Multiple Interface Inheritance
Class có thể implement nhiều interfaces:
interface Walkable {
fun walk() = println("Walking...")
}
interface Swimable {
fun swim() = println("Swimming...")
}
interface Flyable {
fun fly() = println("Flying...")
}
class Duck : Walkable, Swimable, Flyable // Implement 3 interfaces
class Fish : Swimable // Chỉ implement Swimable
class Penguin : Walkable, Swimable {
// Không fly()
}
fun main() {
val duck = Duck()
duck.walk() // Walking...
duck.swim() // Swimming...
duck.fly() // Flying...
}Resolving Conflicts
Khi multiple interfaces có method cùng tên:
interface A {
fun foo() = println("A.foo")
fun bar()
}
interface B {
fun foo() = println("B.foo")
fun bar() = println("B.bar")
}
class C : A, B {
// PHẢI override foo() vì conflict
override fun foo() {
super<A>.foo() // Gọi A.foo()
super<B>.foo() // Gọi B.foo()
}
// PHẢI override bar() vì abstract trong A
override fun bar() {
super<B>.bar() // Có thể dùng default từ B
}
}
fun main() {
val c = C()
c.foo()
// A.foo
// B.foo
c.bar()
// B.bar
}🏛️ Interface vs Abstract Class
| Feature | Interface | Abstract Class |
|---|---|---|
| State (fields) | ❌ Không | ✅ Có |
| Constructor | ❌ Không | ✅ Có |
| Multiple inheritance | ✅ Có | ❌ Không |
| Default implementations | ✅ Có | ✅ Có |
| Visibility modifiers | Chỉ public | Tất cả |
| Dùng khi | Contract, behavior | Shared base + state |
// Interface - chỉ behavior, không có state
interface Logger {
fun log(message: String)
}
// Abstract class - shared implementation + state
abstract class BaseLogger(protected val tag: String) {
abstract fun log(message: String)
protected fun formatMessage(msg: String): String {
return "[$tag] ${System.currentTimeMillis()}: $msg"
}
}
class ConsoleLogger(tag: String) : BaseLogger(tag) {
override fun log(message: String) {
println(formatMessage(message))
}
}🎯 Interface Delegation
Kotlin cho phép delegate interface implementation:
interface Printer {
fun print(text: String)
}
class ConsolePrinter : Printer {
override fun print(text: String) = println(text)
}
// Delegate Printer implementation cho consolePrinter
class Logger(consolePrinter: Printer) : Printer by consolePrinter {
fun logInfo(msg: String) {
print("[INFO] $msg")
}
}
fun main() {
val logger = Logger(ConsolePrinter())
logger.print("Hello") // Hello (delegated)
logger.logInfo("Starting") // [INFO] Starting
}🛠️ Thực hành
Bài tập: Tạo hierarchy với interfaces
// TODO: Tạo:
// - interface Vehicle với properties và methods
// - interface Electric với charge()
// - class Car, ElectricCar, Bicycle implementing phù hợpLời giải:
interface Vehicle {
val brand: String
val maxSpeed: Int
fun start()
fun stop()
fun info() = "$brand (max: $maxSpeed km/h)"
}
interface Electric {
val batteryLevel: Int
fun charge()
fun batteryStatus() = "Battery: $batteryLevel%"
}
class Car(
override val brand: String,
override val maxSpeed: Int = 200
) : Vehicle {
override fun start() = println("$brand: Engine started 🚗")
override fun stop() = println("$brand: Engine stopped")
}
class ElectricCar(
override val brand: String,
override val maxSpeed: Int = 250,
override var batteryLevel: Int = 100
) : Vehicle, Electric {
override fun start() = println("$brand: Silently starting ⚡🚗")
override fun stop() = println("$brand: Stopped")
override fun charge() {
batteryLevel = 100
println("$brand: Fully charged!")
}
}
class Bicycle(
override val brand: String,
override val maxSpeed: Int = 40
) : Vehicle {
override fun start() = println("$brand: Pedaling 🚲")
override fun stop() = println("$brand: Braking")
}
fun main() {
val vehicles: List<Vehicle> = listOf(
Car("Toyota"),
ElectricCar("Tesla"),
Bicycle("Giant")
)
vehicles.forEach { vehicle ->
println(vehicle.info())
vehicle.start()
if (vehicle is Electric) {
println(vehicle.batteryStatus())
}
println()
}
}📱 Trong Android
// Repository pattern
interface UserRepository {
suspend fun getUser(id: Long): User?
suspend fun saveUser(user: User)
suspend fun deleteUser(id: Long)
}
class NetworkUserRepository(private val api: UserApi) : UserRepository {
override suspend fun getUser(id: Long) = api.fetchUser(id)
override suspend fun saveUser(user: User) = api.updateUser(user)
override suspend fun deleteUser(id: Long) = api.deleteUser(id)
}
class LocalUserRepository(private val dao: UserDao) : UserRepository {
override suspend fun getUser(id: Long) = dao.findById(id)
override suspend fun saveUser(user: User) = dao.insert(user)
override suspend fun deleteUser(id: Long) = dao.deleteById(id)
}
// Callback interfaces
interface OnItemClickListener<T> {
fun onItemClick(item: T, position: Int)
fun onItemLongClick(item: T, position: Int) = false // Default
}
// ViewModel interface
interface LoadingState {
val isLoading: Boolean
val error: String?
}
class UserViewModel : ViewModel(), LoadingState {
override var isLoading = false
override var error: String? = null
}⚠️ Lưu ý quan trọng
Ưu tiên Interface over Implementation:
Khi declare types, dùng interface thay vì concrete class:
// ✅ Good - flexible
val list: List<String> = mutableListOf()
// ❌ Avoid - tight coupling
val list: MutableList<String> = mutableListOf()Interface methods mặc định là public:
Không thể có private methods trong interface. Dùng abstract class nếu cần.
✅ Checklist - Tự kiểm tra
Sau bài học này, bạn có thể:
- Hiểu tại sao cần interface (polymorphism, loose coupling)
- Tạo interface với abstract methods
- Sử dụng default implementation
- Tạo interface properties
- Implement multiple interfaces
- Resolve conflicts khi multiple inheritance
- Phân biệt interface vs abstract class
- Áp dụng interface delegation
Tiếp theo: Inheritance