Reputation: 10421
I want to use Kotlin delegation but I don't want to create the delgate outside the delegator. All the samples on delegation all look like this:
interface Worker {
fun doWork()
}
class Supervisor(workerDelegate: Worker) : Worker by workerDelegate {
}
class Delegate : Worker {
override fun doWork() {
// actual work
}
}
fun main() {
val delegate = Delegate()
val supervisor = Supervisor(delegate)
supervisor.doWork() // delegates to delegate
}
But I want to create the Delegate
inside the Supervisor
. Something like this:
class Supervisor : Worker by workerDelegate {
init {
val workerDelegate = Delegate()
}
}
Is something like this possible?
Upvotes: 3
Views: 418
Reputation: 941
You should understand 2 things:
(..., some:IFace) : IFace by some
working only with ctor parameter and only during creation (!) not after creation, it's not "lazy" and it not bind "field" or "property" it binds instance
that was given at creation. So! It's not "delegation" in expected way it's just hint to compiler to substitute all IFace calls to instance that is already in stack.
while init{...}
is a part of construction logic of class it works on members of class, but cannot replace parameters that was already processed from ctor in by
operand.
The most advanced way is just to create "static" factory method to provide some logic to evaluate parameter for ctor.
Assume all this things said before here :
package codes.spectrum.serialization_json.excel
import io.kotlintest.shouldBe
import io.kotlintest.specs.StringSpec
class ItIsNotWorking : StringSpec() {
interface IDo {
fun doIt(): Int
companion object {
val STUB = object :IDo {
override fun doIt(): Int {
error("I am just stub")
}
}
}
}
class Do1 : IDo {
override fun doIt() = 1
}
class Do2 : IDo {
override fun doIt() = 2
}
// i try to make it as parameter in ctor but as var, wishing that it will bind it each call,
// not just during construction
class SuperDo private constructor(param:Int, var doiter: IDo):IDo by doiter{
// imagine that at constructor point you cannot still decide what IDo impl you require
constructor(param: Int) : this(param, IDo.STUB)
init {
// here i try some logic to lately (after construction) to setup doiter
if(param % 2 == 1){
doiter = Do1()
}else{
doiter = Do2()
}
}
}
init {
// that is my expectations
"When with 1 it will be Do1" {
SuperDo(1).doiter.doIt() shouldBe 1 // ok!!!
SuperDo(1).doIt() shouldBe 1 // fail!!!
}
"When with 2 it will be Do2" {
SuperDo(2).doiter.doIt() shouldBe 2 //ok!!!
SuperDo(2).doIt() shouldBe 2 //fail!!
}
// Uffff!!!! It's not working at all (!!!)
}
class NotSuperDo private constructor(val doiter: IDo):IDo by doiter{
// imagine that at constructor point you cannot still decide what IDo impl you require
constructor(param: Int) : this(buildDoiter(param))
companion object {
fun buildDoiter(param: Int) : IDo =
if(param % 2 == 1){
Do1()
}else{
Do2()
}
}
}
init {
// that is my expectations
"not-super When with 1 it will be Do1" {
NotSuperDo(1).doiter.doIt() shouldBe 1 // ok!!!
NotSuperDo(1).doIt() shouldBe 1 // ok!!!
}
"not-super When with 2 it will be Do2" {
NotSuperDo(2).doiter.doIt() shouldBe 2 //ok!!!
NotSuperDo(2).doIt() shouldBe 2 //ok!!
}
// It worked! But it still just better constructor - not case to substitute delegated iface
}
}
Upvotes: 0
Reputation: 5707
just use a private constructor.
class Supervisor private constructor(workerDelegate: Worker) : Worker by workerDelegate {
constructor() : this(Delegate())
}
fun main() {
val delegate = Delegate()
val supervisor = Supervisor()
supervisor.doWork() // delegates to delegate
}
Upvotes: 1
Reputation: 4823
I suppose what you want is this:
class Supervisor : Worker by Delegate(){
}
Upvotes: 3