Kotlin: раскрыть свойства составного класса как общедоступные свойства класса хоста - PullRequest
0 голосов
/ 11 октября 2018

Скажем, у нас есть 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)
}

Возможно ли в Котлине выставить свойства Composite как прямые свойства класса Host?Итак, я хочу написать что-то вроде этого:

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

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

Конечно, можно создать прокси-свойства в Host, но я надеюсь, что Kotlin, как прагматический язык, напрямую поддержит это.

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Решением для этого в Котлине является делегирование .

Вы можете сделать это множеством способов, и это зависит от ваших потребностей, какой из них вы должны выбрать.Сначала вам понадобится interface для вашего Composite:

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

и реализация по умолчанию:

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

Затем вы можете использовать ключевое слово by для делегированияэкземпляр Composite из Host:

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, будет использовать внутреннее поле для вашего делегата, и замена исходного объекта не будет иметь никакого эффекта .Я написал об этом здесь .

Вот как будет выглядеть сгенерированный код Java, если бы composite был var:

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();
   }
}

Примечаниечто установщик не устанавливает $$delegate_0, но composite.

0 голосов
/ 11 октября 2018

Это не возможно напрямую, но вы можете близко имитировать его с помощью реализации путем делегирования , что требует от вас перемещения свойств 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

(запускаемый образец)

Вы можете задать свойство comp private, если вам нужно, или вы можете использовать любой другой экземпляр Composite, который доступенво время инициализации Host в предложении Composite by ... даже создайте некоторый Composite на месте.

...