使用Kotlin实现多接口委托相同的实现

5

情境/问题

我想通过kotlin实现一个具有良好委托功能的库,但是我在想要将两个不同的接口委托给同一实现时遇到了困难。问题是,这两个接口具有共同的方法(其中一个接口是另一个接口的扩展)。

无法更改的库

所以有一个Base接口,它被ExtendedBaseFoo1接口扩展。 还有一个Foo1Impl类,它实现了FooExtendedBase接口,实际上该库中有很多类似此的实现和接口。

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 {
  // ...
}

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

我想扩展这个库并创建自己的接口,以扩展一些 ExtendedBaseFoo[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

这些扩展会抱怨关于“继承了它的多个实现”,因为Foo1ExtendedBase都继承了Base。但实际上很容易判断,因为只有一个可委派的实现:impl: T

我考虑过的事情,但不起作用的/没有用的

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

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

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

2. 类型参数声明的继承(JVM不支持)

如果JVM支持,就可以编写类似于以下内容,但现在不支持:

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

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

但这里,可以看到被压制的警告是问题所在。
4. 用于决定默认实现的语法(在 Kotlin 中不存在)。
class FooBar1Impl<T>
    constructor(impl: T): FooBar1, [default] ExtendedBase by impl, Foo1 by impl
        where T: Foo1, T: ExtendedBase { /* .. */ }

问题

有什么工作流程可以让我免于手动重写所有Base方法?或者有其他任何解决方案使得这种扩展成为可能吗?

假设Base有100个方法需要手动覆盖。

1个回答

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 {
}

那么对于每个显式扩展,我将子类化这个 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() { /* .. */ }
}


最终,这不是一个非常简洁的解决方案,但至少没有错误,我也不必再次实现任何已经实现的方法。然而,警告仍然困扰着我,但我看不到任何解决方法。
如果有任何不需要抑制这些警告的解决方案,那就太好了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接