Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin class delegation, passing this to delegate

Is there any possibility to pass this when delegating class in kotlin?

class SomeFlow : Flow, SmsAuthentication by DefaultSmsAuthentication(this)

It says this does not exist in this context. The other class looks like this:

class DefaultSmsAuthentication(val flow: Flow) : SmsAuthentication
like image 961
Julian Rubin Avatar asked Nov 23 '17 21:11

Julian Rubin


People also ask

How do you use Kotlin delegate?

Kotlin supports “delegation” design pattern by introducing a new keyword “by”. Using this keyword or delegation methodology, Kotlin allows the derived class to access all the implemented public methods of an interface through a specific object.

How do I create a delegate in Kotlin?

You can create delegates as anonymous objects without creating new classes, by using the interfaces ReadOnlyProperty and ReadWriteProperty from the Kotlin standard library. They provide the required methods: getValue() is declared in ReadOnlyProperty ; ReadWriteProperty extends it and adds setValue() .

Why is delegation better than inheritance?

The primary advantage of delegation is run-time flexibility – the delegate can easily be changed at run-time. But unlike inheritance, delegation is not directly supported by most popular object-oriented languages, and it doesn't facilitate dynamic polymorphism.

What are delegated properties?

Simply put, delegated properties are not backed by a class field and delegate getting and setting to another piece of code. This allows for delegated functionality to be abstracted out and shared between multiple similar properties – e.g. storing property values in a map instead of separate fields.


1 Answers

How about injecting this by setter, not by constructor?

For example:

interface SmsAuthentication {

    fun withFlow(flow: Flow)

    fun auth()

}

class DefaultSmsAuthentication() : SmsAuthentication {

    var flow: Flow? = null

    override fun withFlow(flow: Flow) {
        this.flow = flow
    }

    override fun auth() {
        flow?.proceed()
    }

}

class SomeFlow : Flow, SmsAuthentication by DefaultSmsAuthentication() {

    init {
        withFlow(this)
    }

}

However, you need to call withFlow() in constructor by hand every time. You may forget to call it.

You may want to have SmsAuthentication as a property. So you just inject it by lazy and call it in need. I think it's safer way.

class SomeFlow : Flow, SmsAuthentication {

    val auth by lazy { DefaultSmsAuthentication(this) }

    override fun auth() {
        auth.auth()
    }

}

You can also apply Decorator pattern, conversely:

class DefaultSmsAuthenticationFlow(val flow: Flow) :
    SmsAuthentication,
    Flow by flow
{
    override fun auth() {
        // you can use flow as this here
    }
}

fun doAuth(flow: Flow) {
    DefaultSmsAuthenticationFlow(flow).auth()
}
like image 117
Sosuke Ito Avatar answered Oct 15 '22 22:10

Sosuke Ito