我有一组组件接口
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 接口
interface TestAdder<T> {
fun add_f(p: T) {} //default impl
}继承以将上述组件添加到相应的(功能)集合接口的
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>中定义的功能。
interface IOTestSet<I, O> : ITestSet<I>, OTestSet<O>, TestAdder<IOTest<I, O>> {
fun io_f1(p: I): O
...
}但是很明显,TestAdder<T>接口在继承链中引入了不一致性。
这闻起来像是一个古老的原型范式(甚至可能是XY)问题,但我似乎还是要问:
问:如何构建这个继承链?
或者什么是既定的/更好/更少,而不是不必要的复杂/更优雅的设计模式?
发布于 2022-09-01 10:47:07
至于为什么这不起作用,这是因为您是从同一个接口继承的,只是具有不同的类型参数。here解释了为什么你不能这么做。
作文
当继承不起作用时,我们可以尝试组合。(另见:"Prefer Composition Over Inheritance")
与其让ITestSet和OTestSet继承TestAdder (这是“从同一个接口继承但具有不同类型参数”问题的根本原因),不如向ITestSet、OTestSet以及IOTestSet添加TestAdder类型的get只读属性。
然后IOTestSet将能够继承ITestSet和OTestSet。完整的代码如下:
// 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>,只需:
class Foo: ITestSet<String> {
override val i_v: String = "Some String"
override val inputAdder = object: TestAdder<ITest<String>> {
// implementation goes here...
}
}请注意,可以为inputAdder提供默认实现。
interface ITestSet<I> {
val i_v: I
val inputAdder: TestAdder<ITest<I>> get() = object: TestAdder<ITest<I>> {
// implement your thing here...
}
...
}但是这会在每次访问inputAdder时重新创建对象,这可能不是您想要的语义。
这就引出了这个设计与原始设计的另一个不同之处:允许实现以他们喜欢的任何方式实现inputAdder、outputAdder和ioAdder。这意味着它们不一定被实现,例如,每个ITestSet都有相同的inputAdder,就像在您的原始设计中一样,其中每个ITestSet的"inputAdder“总是它自己。当然,如果您完全控制代码,这不是问题。
https://stackoverflow.com/questions/73567454
复制相似问题