Kotlin:将复合类属性公开为公共宿主类属性

问题描述 投票:2回答:2

说我们有一个Composite

class Composite(val one: Int, val two: Int)

还有一个Host课程

class Host(val comp: Composite)

现在我们可以打印Composite对象的属性

fun hostTest() {
    val comp = Composite(2, 3)
    val hst = Host(comp)

    println(hst.comp.one)
    println(hst.comp.one)
}

在Kotlin中有可能将Composite属性作为Host类的直接属性来暴露吗?所以,我想写这样的东西:

fun hostTest() {
    val comp = Composite(2, 3)
    val hst = Host(comp)

    println(hst.one)
    println(hst.one)
}

当然,可以在Host中创建代理属性,但我希望Kotlin作为一种实用语言直接支持这一点。

kotlin properties composition class-design
2个回答
1
投票

Kotlin的解决方案是delegation

您可以通过多种方式实现这一目标,这取决于您的需求,您应该选择哪一种。首先,你需要一个interface为你的Composite

interface Composite {
    val one: Int
    val two: Int
}

和默认实现:

class DefaultComposite(override val one: Int,
                       override val two: Int) : Composite

然后你可以使用by关键字委托CompositeHost实例:

class Host(val composite: Composite) : Composite by composite

如果你有composite的合理默认值:

class CompositeWithDefaults(override val one: Int = 1,
                            override val two: Int = 2) : Composite

那么你甚至不必将Composite作为构造函数参数传递:

class Host() : Composite by CompositeWithDefaults()

或者您可以将其字段传递给Host

class Host(one: Int, two: Int) : Composite by DefaultComposite(one, two)

或者有一个默认值:

class Host(composite: Composite = CompositeWithDefaults()) : Composite by composite

但请注意:您不应该委托给可变的属性,因为使用by时生成的字节码将为您的委托使用内部字段,替换原始对象将不起作用。我写过关于这个here的文章。

如果compositevar,这就是生成的Java代码的样子:

public final class Host implements Composite {
   @NotNull
   private Composite composite;
   // $FF: synthetic field
   private final Composite $$delegate_0;

   @NotNull
   public final Composite getComposite() {
      return this.composite;
   }

   public final void setComposite(@NotNull Composite var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      this.composite = var1;
   }

   public Host(@NotNull Composite composite) {
      Intrinsics.checkParameterIsNotNull(composite, "composite");
      super();
      this.$$delegate_0 = composite;
      this.composite = composite;
   }

   public int getOne() {
      return this.$$delegate_0.getOne();
   }

   public int getTwo() {
      return this.$$delegate_0.getTwo();
   }
}

请注意,setter不会设置$$delegate_0,而是设置composite


0
投票

它不是直接可能的,但你可以通过implementation by delegation来密切模拟它,这需要你将Composite的属性移动到一个接口:

interface Composite {
    val one: Int
    val two: Int
}

class CompositeImpl(
    override val one: Int, 
    override val two: Int
) : Composite

class Host(val comp: Composite) : Composite by comp

(runnable sample)

如果需要,你可以制作comp属性private,或者你可以使用Composite初始化时间在Host子句中可用的任何其他Composite by ...实例,甚至可以在原地构建一些Composite

© www.soinside.com 2019 - 2024. All rights reserved.