Self type
You can implement self type through generics.
self type with abstract classes
open class Query1{
var prop0: Int = 0
protected set
abstract class QueryBuilderA<SELF>
where SELF : QueryBuilderA<SELF> {
protected abstract var instance: Query1
abstract val builder: SELF
fun setProp0(v: Int): SELF =
builder.apply { instance.prop0 = v }
abstract fun build(): Query1
}
}
class QueryExt : Query1() {
var prop1: Int = 0
protected set
// if you don't like where use:
// abstract class QueryBuilderA2<SELF>: QueryBuilderA<QueryBuilderA2<SELF>>()
abstract class QueryBuilderA2<SELF> : QueryBuilderA<SELF>()
where SELF : QueryBuilderA2<SELF> {
override var instance: Query1 = QueryExt()
fun setProp1(v: Int): SELF = builder.apply {
instance.apply { this as QueryExt; prop1 = v }
}
}
// concrete builder
class Builder : QueryBuilderA2<Builder>() {
override val builder: Builder = this
override fun build(): QueryExt = instance as QueryExt
}
}
// using
val q = QueryExt.Builder()
.setProp0(1)
.setProp1(2)
.build()
self type with interfaces
// interface with self type
interface QueryBuilderI<SELF>
where SELF : QueryBuilderI<SELF>{
// or you can use: fun getSelf(): SELF
val builder : SELF
fun someDefaultMethod(arg: Int): SELF {
return builder
}
}
// extend interface with self type
interface QueryBuilderI2<SELF>: QueryBuilderI<SELF>
where SELF : QueryBuilderI2<SELF<{
fun setProp1(arg: Int): SELF
fun setProp2(arg: Int): SELF
}
// concrete class
class QB2 : QueryBuilderI2<QB2> {
override val builder: QB2 = this
override fun setProp2(arg: Int): QB2 {
return builder
}
override fun setProp1(arg: Int): QB2 {
return builder
}
}
// using
QB2().someDefaultMethod(1) // ok, method return QB2
.setProp2(2) // so we can call setProp2/setProp1
.someDefaultMethod(2)
.setProp1(1)
// create variable
val builder : QueryBuilderI2<QB2> = QB2()
builder.someDefaultMethod(1).setProp1(1)
// now setProp1/setProp2 methods are not available
// useful when you want to restrict client
// by the first interface
val builder2 : QueryBuilderI<QB2> = builder
builder2.someDefaultMethod(2)