Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to design a complex class which incude some classes to make expansion easily in future in Kotlin?

Tags:

java

kotlin

I'm a beginner of Kotlin, I use Code A to define a complex class MDetail, and use Code B to create a object aMDetail1, it can work.

But the data construction is too bad to expand, if I include a new data class such as ScreenDef in MDetail just like Code C, all old code have to be rewriten.

Is there a good data construction for a complex class which include some classes ? I hope to the data construction can be expansion easily in future!

Code A

data class BluetoothDef(val Status:Boolean=false)
data class WiFiDef(val Name:String, val Status:Boolean=false)

data class MDetail (
        val _id: Long,
        val bluetooth: BluetoothDef,
        val wiFi:WiFiDef
)

Code B

var mBluetoothDef1= BluetoothDef()
var mWiFiDef1= WiFiHelper(this).getWiFiDefFromSystem()
var aMDetail1= MDetail(7L,mBluetoothDef1,mWiFiDef1)

Code C

data class BluetoothDef(val Status:Boolean=false)
data class WiFiDef(val Name:String, val Status:Boolean=false)
data class ScreenDef(val Name:String, val size:Long)
... 

data class MDetail (
        val _id: Long,
        val bluetooth: BluetoothDef,
        val wiFi:WiFiDef
        val aScreenDef:ScreenDef        
        ...
)

The following code is based what s1m0nw1 said, I think it's easy to extend for future. Thanks!

Is there other more better way?

Version 1 Code

interface DeviceDef

data class BluetoothDef(val Status: Boolean = false) : DeviceDef
data class WiFiDef(val Name: String, val Status: Boolean = false) : DeviceDef
data class ScreenDef(val Name: String, val size: Long) : DeviceDef

class MDetail(val _id: Long, val devices: MutableList<DeviceDef>) {
    inline fun <reified T> getDevice(): T {
        return devices.filterIsInstance(T::class.java).first()
    }
}

class UIMain : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.layout_main)

        val btD = BluetoothDef(true)
        val wfD = WiFiDef("MyWifi")
        val xSc = ScreenDef("MyScreen", 1)
        val m = MDetail(7L, mutableListOf(btD, wfD, xSc))


        handleBluetoothDef(m.getDevice<BluetoothDef>())
        handleWiFiDef(m.getDevice<WiFiDef>())
        handleScreenDef(m.getDevice<ScreenDef>())
    }

    fun handleBluetoothDef(mBluetoothDef:BluetoothDef){ }    
    fun handleWiFiDef(mWiFiDef:WiFiDef){ }    
    fun handleScreenDef(mScreenDef:ScreenDef){ }
}

Version 2 Code (Expansion)

interface DeviceDef

data class BluetoothDef(val Status: Boolean = false) : DeviceDef
data class WiFiDef(val Name: String, val Status: Boolean = false) : DeviceDef
data class ScreenDef(val Name: String, val size: Long) : DeviceDef

data class TimeLine(val Name: String): DeviceDef  //Extend

class MDetail(val _id: Long, val devices: MutableList<DeviceDef>) {
    inline fun <reified T> getDevice(): T {
        return devices.filterIsInstance(T::class.java).first()
    }
}

class UIMain : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.layout_main)

        val btD = BluetoothDef(true)
        val wfD = WiFiDef("MyWifi")
        val xSc = ScreenDef("MyScreen", 1)

        val aTe = TimeLine("MyTimeline")  //Extend

        val m = MDetail(7L, mutableListOf(btD, wfD, xSc,aTe)) //Modified


        handleBluetoothDef(m.getDevice<BluetoothDef>())
        handleWiFiDef(m.getDevice<WiFiDef>())
        handleScreenDef(m.getDevice<ScreenDef>())

        handleTimeLine(m.getDevice<TimeLine>()) //Extend
    }

    fun handleBluetoothDef(mBluetoothDef:BluetoothDef){}    
    fun handleWiFiDef(mWiFiDef:WiFiDef){ }    
    fun handleScreenDef(mScreenDef:ScreenDef){ }           
    fun handleTimeLine(mTimeLine:TimeLine){}  //Extend

Help

I have to replace interface with open class because I can't unserialize MDetail object from json string GSON.

but the fun inline fun <reified T> getDevice(): T{ } can't return correct result, how can I modify? Thanks!

open class DeviceDef

data class BluetoothDef(val status:Boolean=false):  DeviceDef()
data class WiFiDef(val name:String, val status:Boolean=false) : DeviceDef()

data class MDetail(val _id: Long, val deviceList: MutableList<DeviceDef>)
{
    inline fun <reified T> getDevice(): T {        
        return deviceList.filterIsInstance(T::class.java).first()
    }
}
like image 780
HelloCW Avatar asked Dec 01 '17 03:12

HelloCW


1 Answers

I suggest to do the following: Your units (Wifi, Bluetooth etc.) should be abstracted by an interface (at least as a marker), which could be named DeviceDef.

interface DeviceDef
data class BluetoothDef(val Status: Boolean = false) : DeviceDef
data class WiFiDef(val Name: String, val Status: Boolean = false) : DeviceDef
data class ScreenDef(val Name: String, val size: Long) : DeviceDef 

The MDetail class can be instantiated with a variable list of these devices, so that no modifications are needed when new devices, such as ScreenDef, are added:

class MDetail(val _id: Long, val devices: List<DeviceDef>)

Inside MDetail, you can provide a method for filtering these devices:

class MDetail(val _id: Long, val devices: List<DeviceDef>) {

    inline fun <reified T> getDevice(): T {
        return devices.filterIsInstance(T::class.java).first()
    }
}

Now, it's pretty simple to work with the WifiDef for example:

fun main(args: Array<String>) {
    val btD = BluetoothDef()
    val wfD = WiFiDef("")
    val m = MDetail(7L, listOf(btD, wfD, ScreenDef("", 1)))
    println(m.getDevice<WiFiDef>())
}

I hope this helps. If not, it might be necessary that you provide more details on how MDetail is supposed to work.

like image 88
s1m0nw1 Avatar answered Nov 06 '22 14:11

s1m0nw1