Преобразование дочерних параметров конструктора для родительского конструктора в Kotlin - PullRequest
0 голосов
/ 01 мая 2019

Я ветеран Java, который изучает Kotlin. Я немного озадачен тем, как взять параметры конструктора, предоставленные дочернему классу, и преобразовать их в параметры, требуемые родительским классом. Проблема возникает, когда параметры, предоставленные ребенку, не подходят для родителя.

Например, когда у меня IntelliJ IDEA, преобразовать следующее в Kotlin ...

class Base
{
    final int w;
    final int h;

    Base(int w, int h)
    {
        this.w = w;
        this.h = h;
    }
}

class Derived extends Base
{
    Derived(int x)
    {
        // some complex derivation
        Converter c = new Converter(x);
        super(c.a, c.b);
    }
}

class Converter
{
    final int a;
    final int b;

    Converter(int x)
    {
        a = x + 2;
        b = x - 2;
    }
}

Я получаю следующее, включая ошибку в указанной позиции о том, что параметры не были переданы для w и h ...

open class Base(val w: Int, val h: Int)

class Derived(x: Int) : Base() {
    //                       ^ error
    init {
        // some complex derivation
        val c = Converter(x)
        // How do I provide c.a and c.b?
    }
}

class Converter(x: Int) {
    val a: Int
    val b: Int

    init {
        a = x + 2
        b = x - 2
    }
}

Каково общее решение этой проблемы? (Понятно, что я не делаю ничего такого простого, как показано здесь. Я упростил просто, чтобы представить проблему.)

Ответы [ 2 ]

1 голос
/ 01 мая 2019

Я бы предложил использовать более простой закрытый конструктор и добавить фабричный метод для выполнения преобразования, например:

class Derived private constructor(val w: Int, val h: Int) : Base(w, h) {
    companion object {
        operator fun invoke(x: Int): Derived {
            // Some complex derivation…
            val c = Converter(x)
            return Derived(c.a, c.b)
        }
    }
}

Это можно вызвать точно таким же образомв качестве конструктора, например, val d = Derived(1), но он имеет несколько преимуществ:

  • Он может выполнить много обработки перед вызовом конструктора.

  • При необходимости он может возвращать кэшированные значения вместо новых экземпляров.

  • Может возвращать подкласс.(Таким образом, Derived может быть абстрактным классом - или вам он вообще может не понадобиться.) Точный класс может отличаться между вызовами и даже может быть анонимным типом.

  • У него может быть имя.Это особенно важно, если вам нужно несколько методов с одинаковыми параметрами.(Например, объект Point, который может быть построен из прямоугольных или полярных координат.) Однако фабричный метод не нуждается в конкретном имени;если вы реализуете метод invoke() в сопутствующем объекте (как описано выше), вы можете вызывать его точно так же, как и конструктор.

  • Это облегчает изменение реализациикласса, не затрагивая его открытый интерфейс.

Однако есть один недостаток:

  • Он не может использоваться конструкторами подкласса.

В отличие от ответа, основанного на свойствах, он не требует каких-либо изменений для остальной части класса и не удерживает объект Convertor;это просто другой способ вызова конструктора.

(В некоторых случаях вам может не потребоваться сделать первичный конструктор частным; он может предоставить альтернативу фабричному методу (методам), если подписине совпадают.)

0 голосов
/ 01 мая 2019

Комментарий JB Nizet выше поставил меня на правильный путь: вы не можете сделать это таким же образом в Java. Я связываю себя в узлах, пытаясь делать вещи по-котлински. В этом случае я пытаюсь использовать свойства везде, где я использую методы доступа в Java.

Одно из решений - сделать базовые свойства абстрактными:

abstract class Base {
    abstract val w: Int
    abstract val h: Int

    // base implementation
}

class Derived(x: Int) : Base() {
    private val c = Converter(x)

    override val w: Int
        get() = c.a

    override val h: Int
        get() = c.b
}

class Converter(x: Int) {
    // implementation not relevant here
    val a = x + 2
    val b = x - 2
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...