首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通用接口继承

通用接口继承
EN

Stack Overflow用户
提问于 2022-09-01 09:56:30
回答 1查看 49关注 0票数 2

我有一组组件接口

代码语言:javascript
复制
interface ITest<I> {
    operator fun invoke(p: I)
}

interface OTest<O> {
    operator fun invoke(): O
}

interface IOTest<I, O> {
    operator fun invoke(p: I): O
}

以及相应的functional 接口

代码语言:javascript
复制
interface TestAdder<T> {
    fun add_f(p: T) {}  //default impl
}

继承以将上述组件添加到相应的(功能)集合接口

代码语言:javascript
复制
interface ITestSet<I> : TestAdder<ITest<I>> {
    val i_v: I
    
    fun i_f1(p: I) {}  // default impl
    fun i_f2(p: I) {}  // default impl
    fun i_f3(p: I) {}  // default impl
}

interface OTestSet<O> : TestAdder<OTest<O>> {
    val o_v: O
    
    fun o_f1(p: O) {}  // default impl
    fun o_f2(p: O) {}  // default impl
    fun o_f3(p: O) {}  // default impl
}

interface IOTestSet<I, O> : TestAdder<IOTest<I, O>> {
    val i_v: I
    val o_v: O
    
    // same as ITestSet<I>
    fun i_f1(p: I) {}  // default impl
    fun i_f2(p: I) {}  // default impl
    fun i_f3(p: I) {}  // default impl 
    
    // same as OTestSet<O>
    fun o_f1(p: O) {}  // default impl
    fun o_f2(p: O) {}  // default impl
    fun o_f3(p: O) {}  // default impl

    fun io_f1(p: I): O
    ...
}

到目前为止,还没有必要:理想情况下,IOTestSet<I, O>应该继承ITestSet<I>OTestSet<O>中定义的功能。

代码语言:javascript
复制
interface IOTestSet<I, O> : ITestSet<I>, OTestSet<O>, TestAdder<IOTest<I, O>> {
    fun io_f1(p: I): O
    ...
}

但是很明显,TestAdder<T>接口在继承链中引入了不一致性。

这闻起来像是一个古老的原型范式(甚至可能是XY)问题,但我似乎还是要问:

问:如何构建这个继承链?

或者什么是既定的/更好/更少,而不是不必要的复杂/更优雅的设计模式?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-01 10:47:07

至于为什么这不起作用,这是因为您是从同一个接口继承的,只是具有不同的类型参数。here解释了为什么你不能这么做。

作文

当继承不起作用时,我们可以尝试组合。(另见:"Prefer Composition Over Inheritance")

与其让ITestSetOTestSet继承TestAdder (这是“从同一个接口继承但具有不同类型参数”问题的根本原因),不如向ITestSetOTestSet以及IOTestSet添加TestAdder类型的get只读属性。

然后IOTestSet将能够继承ITestSetOTestSet。完整的代码如下:

代码语言:javascript
复制
// I have added variance modifiers where appropriate
interface ITest<in I> {
    operator fun invoke(p: I)
}

interface OTest<out O> {
    operator fun invoke(): O
}

interface IOTest<in I, out O> {
    operator fun invoke(p: I): O
}

interface TestAdder<in T> {
    fun add_f(p: T) {}  //default impl
}

interface ITestSet<I> {
    val i_v: I
    val inputAdder: TestAdder<ITest<I>>
    fun i_f1(p: I) {}  // default impl
    fun i_f2(p: I) {}  // default impl
    fun i_f3(p: I) {}  // default impl
}

interface OTestSet<O> : TestAdder<OTest<O>> {
    val o_v: O
    val outputAdder: TestAdder<OTest<O>>
    fun o_f1(p: O) {}  // default impl
    fun o_f2(p: O) {}  // default impl
    fun o_f3(p: O) {}  // default impl
}

interface IOTestSet<I, O> : ITestSet<I>, OTestSet<O> {
    val ioAdder: TestAdder<IOTest<I, O>>
    fun io_f1(p: I): O
}

实现接口

从我所看到的情况来看,您仍然可以像以前一样实现这组新的接口--例如,要实现ITestSet<String>,只需:

代码语言:javascript
复制
class Foo: ITestSet<String> {
    override val i_v: String = "Some String"
    override val inputAdder = object: TestAdder<ITest<String>> {
        // implementation goes here...
    }
}

请注意,可以为inputAdder提供默认实现。

代码语言:javascript
复制
interface ITestSet<I> {
    val i_v: I
    val inputAdder: TestAdder<ITest<I>> get() = object: TestAdder<ITest<I>> {
        // implement your thing here...
    }
    ...
}

但是这会在每次访问inputAdder时重新创建对象,这可能不是您想要的语义。

这就引出了这个设计与原始设计的另一个不同之处:允许实现以他们喜欢的任何方式实现inputAdderoutputAdderioAdder。这意味着它们不一定被实现,例如,每个ITestSet都有相同的inputAdder,就像在您的原始设计中一样,其中每个ITestSet的"inputAdder“总是它自己。当然,如果您完全控制代码,这不是问题。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73567454

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档