Kotlin:委托具有相同实现的多个接口

Jan*_*Jan 5 delegates interface kotlin

情况/问题

我想通过 kotlin 扩展一个具有良好委托功能的库,但我陷入了一个地方,我想将两个不同的接口委托给同一个 impl。问题是,这两个接口具有共同的方法(一个扩展了另一个)。

我无法更改的库

所以存在一个由和接口Base扩展的接口。而 a实现了和,实际上库中有很多类似的实现和接口。ExtendedBaseFoo1Foo1ImplFooExtendedBase

interface Base: {
  fun doBase()
  fun doBase2()
  // .. lots of methods
  fun doBaseN()
}

interface ExtendedBase: Base {
  fun doExtended()
  fun doExtended2()
  // .. lots of methods
  fun doExtendedN()
}

interface Foo1: Base {
  fun doFoo1()
}

class Foo1Impl: Foo1, ExtendedBase {
  // some impl for doBase, doExtended and doFoo1
}

interface Foo2: Base {
  fun doFoo2()
}

class Foo2Impl: Foo2, ExtendedBase {
  // ...
}

// ... lots of interfaces and impls

interface FooN: Base {
  fun doFooN()
}

class FooNImpl: FooN, ExtendedBase {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

扩展该库(这就是我想做的)

我想扩展这个库并创建我自己的接口来扩展以下内容的ExtendedBase功能Foo[1..N]


interface FooBar1: Foo1 {
  fun doFooBar1()
}

class FooBar1Impl<T>
    constructor(impl: T): FooBar1, ExtendedBase by impl, Foo1 by impl
        where T: Foo1, T: ExtendedBase
{

    override fun doFooBar1() {
        println("foobar1")
    }
}

//.. a lot of other extensions like FooBar[2..N] that all extended the bases with the same logic
Run Code Online (Sandbox Code Playgroud)

这些扩展会抱怨inheriting multiple implementations of it因为两者Foo1ExtendedBase扩展Base。但实际上它很容易决定,因为只有一种实现可以委托给:impl: T

我想到的有效/无效的事情

1. 多接口实现的语法(kotlin 中不存在)

如果有一个多接口实现的语法,可能会像这样:

class FooBar1Impl<T>
    constructor(impl: T): FooBar1, (ExtendedBase, Foo1) by impl
        where T: Foo1, T: ExtendedBase
{ /* ... */ }
Run Code Online (Sandbox Code Playgroud)

2.类型参数声明的继承(对于jvm来说不可能)

如果 jvm 可以的话,我们可以写这样的东西,但事实并非如此:

class FooBar1Impl<T>
    constructor(impl: T): FooBar1, T by impl
        where T: Foo1, T: ExtendedBase
{ /* ... */ }
Run Code Online (Sandbox Code Playgroud)

3. 几乎可能:可以扩展的基础对象(仍然有问题)

open class BaseExtension constructor(impl: Base) : Base by impl

@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
class FooBar1Impl<T>
    constructor(impl: T): BaseExtension(impl), FooBar1
        where T: Base, T: ExtendedBase
Run Code Online (Sandbox Code Playgroud)

但在这里你可以看到被抑制的警告就是问题所在。

4. 决定默认impl的语法(kotlin中不存在)

class FooBar1Impl<T>
    constructor(impl: T): FooBar1, [default] ExtendedBase by impl, Foo1 by impl
        where T: Foo1, T: ExtendedBase { /* .. */ }
Run Code Online (Sandbox Code Playgroud)

问题

是否有任何工作流程可以让我免于Base手动覆盖所有方法?或者任何其他解决方案可以使这种扩展成为可能?

想象一下Base有类似的100方法,我需要手动重写。

Jan*_*Jan 1

好吧,我想我现在可能已经找到了解决方案:

首先,我将创建一个基本扩展类结构,它将方法从 和 委托BaseBaseExtension同一个构造函数属性。我需要/想要取消对此的警告......

出现警告是因为 kotlin 无法看到超类方法都委托给了impl该实现将重写方法委托给的同一实现:

open class BaseExtension<in T: Base>
    constructor(private val impl: T) : Base by impl

@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
open class Extension<in T>
    constructor(private val impl: T) : BaseExtension<T>(impl), ExtendedBase by impl
        where T: Base, T: ExtendedBase {
}
Run Code Online (Sandbox Code Playgroud)

然后,对于每个显式扩展,我将对其进行子类化Extension并实现显式扩展的接口,如下所示:

interface FooBar1: Foo1 {
    fun doFooBar1()
}

@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
class FooBar1Impl<in T>
constructor(private val impl: T) : FooBar1, Extension<T>(impl), Foo1 by impl
    where T: Base, T: ExtendedBase, T: Foo1
{
    fun doFooBar() { /* .. */ }
}

Run Code Online (Sandbox Code Playgroud)

最后,这不是一个非常简洁的解决方案,但至少没有错误,而且我不必再次实现任何已经实现的方法。虽然这个警告仍然让我烦恼,但我看不到任何解决办法。


如果有人提出了不包含这些需要抑制的警告的解决方案,那就太好了。