Delegate là gì nhỉ? Tại sao lại là Delegate? Đúng như cái tên, Delegate là một design pattern mà bạn ủy quyền xử lý logic của Class hiện tại cho một Object/Class khác. Delegate thường được sử dụng để tách logic code theo việc của nó (separate concerns) hoặc common hóa một đoạn logic.
Bài viết này sẽ giúp bạn tìm hiểu cơ bản về Delegate trong Kotlin và cách sử dụng khái niệm này. Trong Kotlin, có 2 cách để sử dụng Delegate
– Interface/Class Delegation
– Delegate Properties
Delegate là cách bạn cho phép một object khác xử lý một logic cho object hiện tại
Interface/Class Delegation
Với cách thứ nhất, chúng ta sẽ sử dụng một interface làm abstract cho một object và truyền object đó vào phần khai báo implement thông qua keyword by. Bằng cách này, các abstract methods (method của interface) sẽ chạy code của delegating object!
interface CameraOptimization {
fun optimize()
}
object XiaomiDevicesOptimization : CameraOptimization {
override fun optimize() {
TODO("do something for Xiaomi devices")
}
}
object DefaultDevicesOptimization : CameraOptimization {
override fun optimize() {
TODO("do something for others devices")
}
}
class CameraManager(optimization: CameraOptimization) : CameraOptimization by optimization {
fun cameraFocus() {
//todo: focus camera
}
}
Đây là cách setup cơ bản của Interface/Class Delegation. Như các bạn thấy thì implementation của method optimize() không trực tiếp xuất hiện ở trong class CameraManager mà sẽ được delegate đến object truyền vào bằng keyword by.
class CameraActivity : BaseActivity() {
private lateinit var _cameraManager: CameraManager
private fun initView() {
val vendor = android.os.Build.MANUFACTURER
val config = when {
vendor.equals("Xiaomi", ignoreCase = true) -> XiaomiDevicesOptimization
else -> DefaultDevicesOptimization
}
_cameraManager = CameraManager(config)
_cameraManager.optimize()
_cameraManager.cameraFocus()
}
}
Khi method optimize() được gọi, nó sẽ delegate đến Config của XiaomiDevicesOptimization hoặc DefaultDevicesOptimization tùy theo device đó là gì. Với cách tiếp cận này logic của CameraManager vẫn có khả năng tối ưu mà không cần phải quan tâm rằng nó sinh ra cho vendor cụ thể nào cả. Đồng thời cũng tăng khả năng mở rộng của Class này hơn. Nếu app của bạn quyết định support optimize thêm cả anh zai Samsung cũng oke luôn, code thêm 1 class và 1 dòng duy nhất.
Delegate Properties
Chắc bạn đã từng sử dụng rất nhiều lần lazy trong kotlin rồi đúng không? Delegate đó :v Delegate Properties là việc bạn implement operator getValue (có thể thêm cả setValue luôn nếu bạn muốn nó set được cả value) của một class. Hoặc một cách khác tường mình hơn là implement interface ReadWriteProperty/ReadOnlyProperty. Class đó sẽ trở thành Delegate. Vẫn là keyword by, chúng ta khai báo một biến với Delegate thông qua by.
class IntNaturalSet : ReadWriteProperty<Any, Int> {
private var _value: Int = 0
override fun getValue(thisRef: Any, property: KProperty<*>): Int {
return _value
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) {
_value = if(value < 0) 0 else value
}
}
Trong ví dụ đơn giản này chúng ta đã ủy quyền getter setter của biến cho class IntNaturalSet can thiệp và xử lý logic. Bên cạnh việc ủy quyển xử lý logic getter (setter) thì Delegate cũng có thể access đến Class chứa biến được delegate thông qua param thisRef(Chính là generic T trong ReadWriteProperty/ReadOnlyProperty). Có thể là built-in delegate cho một Type hoặc ép kiểu thisRef trong logic của getter setter để có thể sử dụng param này.
Ứng dụng của Delegate Properties rất rộng, chúng ta có thể custom cho logic in/out data như shared preferences, cache…
Trong Androidx/Kotlin cơ bản cũng có vài delegate như lazy, viewModels, activityViewModels…
Summary
Delegate là một phương pháp khá hay trong lập trình giúp chúng ta tối ưu logic source code. Một source base có thể sẽ clean hơn nếu rút gọn các common logic hay boilerplate code. Một class có thể tăng tính mở rộng trong tương lai. Một project có thể sẽ triển khai nhanh hơn nhờ những common và khả năng scalable tốt. Lần tới nếu như bạn gặp phải một vấn đề có thể xử lý bằng Delegate, cứ thử xem sao nhé!
Hi vọng bài viết giúp bạn có thêm chút kiến thức trong chặng đường của một Engineer :3!