Sunday 12 September 2021

DSL Code References

We should use DSL to simplify and improve the complexity of the app and make the code more readable, Before jumping into writing our own DSL we need to aware about the concept of lambda with receiver, invoke and operator.

Assume an example we have a class called Device, Please see below different ways how the object got initialized

class Device() {
    var id: Int = 0
    var name: String = ""
    var make: String = ""

    fun printDeviceInfo() {
        println("ID:  $id | Name: $name | Make: $make")
    }

    operator fun invoke(device: Device.() -> Unit): Device {
        device()
        return this
    }
}

Now, to instantiate the Class we can create an object like below ways,

// Traditional Way
    val env = Device()
    env.id = 102
    env.name = "5.4 GHz Wifi"
    env.make = "Amazon-Cable"
    env.printDeviceInfo()

// Invoke Way
    val en = Device()
    val obj = en {
        id = 102
        name = "5.4 GHz Wifi"
        make = "Amazon-Cable"
    }
    obj.printDeviceInfo()
    en.printDeviceInfo()

There is also other way where we are able to do without using invoke operator function, but here we can't use the traditional way of object creation. Since we pass it as parameter to the class primary constructor and followed by init method should call the same.

class Device(device: Device.() -> Unit) {
    var id: Int = 0
    var name: String = ""
    var make: String = ""

    fun printDeviceInfo() {
        println("ID:  $id | Name: $name | Make: $make")
    }

    init {
        device()
    }
}

val device = Device {
        id = 102
        name = "5.4 GHz Wifi"
        make = "Amazon-Cable"
    }
    device.printDeviceInfo()

Here we can also use it on the Data class also, but we should declare the constructor param as val/var, whereas it is not required on the normal model class like above.

data class User(val obj: User.() -> Unit) {
    var id: String = "NA"
    var age: Long = 0

    init {
        obj()
    }
}

fun main() {
    val userObj = User {}
    printUser(userObj)
    val usersList = listOf(userObj, User {
        id = "ABC567"
        age = 28
    }, User {
        id = "BCG678"
        age = 24
    }, User {
    })

    usersList[0].id = "BGH905"
    usersList.forEach(::printUser)
}

fun printUser(user: User) {
    println("Id: ${user.id}|| Age: ${user.age.takeIf { it > 0 } ?: "NA"}")
}

Good Luck :-) Happy Coding !!!

No comments: