При реализации интерфейса обращайтесь к super в значениях параметров конструктора по умолчанию - PullRequest
0 голосов
/ 25 мая 2018

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

interface Repository {
    val name : String
    val pattern : String
        get() = "foo/bar/baz"
    var url : String
        get() = "http://mycompanyrepo.com/$name"

    fun add() {
        TODO("do something interesting here")
    } 
}

Теперь есть несколько конкретных реализаций, которые просто используют большинство значений по умолчанию.Однако я также хочу предоставить ConfigurableRepository, который обеспечивает большую гибкость в других проектах, которые хотят настроить это во время выполнения, основываясь на других пользовательских параметрах.

Как я могу создать первичный конструктор с необязательными параметрами?

Я надеялся что-то вроде:

class ConfigurableRepo(var name, var pattern, var url) {
   ...
}

Отредактировано для пояснения

Намерение здесь состоит в том, чтобы использовать первичное поведение конструктора, где именованные параметры являются необязательными.Точнее, name, pattern и url являются необязательными для всех, кто вызывает конструктор, и по умолчанию они будут получать геттеры интерфейса.Но я, очевидно, пытаюсь заставить Kotlin interface соответствовать этой модели, и это, вероятно, ошибка пользователя Kotlin noob, поскольку у меня в конечном счете нет доступа к super здесь.

Из класса docs

Фактически, для объявления свойств и их инициализации из основного конструктора, Kotlin имеет краткий синтаксис:

class Person(val firstName: String, val lastName: String, var age: Int) {      
    // ...
}

Я, кажется, получаюошибки, которые скрывают члены супертипа и требуют модификатор override.Если я пытаюсь переопределить супертип и затем указать значение по умолчанию, он жалуется, что в этом контексте супертипы недоступны.

Можно ли это сделать только во вторичном конструкторе с изменяемыми значениями?

Я также открыт для предложений / отзывов о лучших способах предоставления интерфейса, который поддерживает конфигурациюсверх соглашения.Наиболее важным аспектом является то, что интерфейс всегда предоставляет значения по умолчанию для соглашения.Или, проще говоря:

Есть ли лучший способ?

Ответы [ 4 ]

0 голосов
/ 27 мая 2018

Если вы намерены использовать значения по умолчанию для параметров конструктора по умолчанию, например, такого (псевдокод, который не компилируется):

class ConfigurableRepo(
    override var name, 
    override var pattern = super.pattern, 
    override var url = super.url
) {
    ...
}

Тогда по умолчанию будет использоваться значение "null"шаблон », который всегда можно использовать, когда желаемое значение по умолчанию не может быть выражено в объявлении метода.В вашем случае это может сработать так:

class ConfigurableRepo (
        override val name: String,
        _url: String? = null,
        _pattern: String? = null
): Repository {
    override val pattern = _pattern ?: super.pattern
    override var url = _url ?: super.url

    // ... more code ...
}

Как видите, трюк работает с val, а также с var свойствами и полями.Свойство name, которое не имеет значения по умолчанию в интерфейсе, реализовано с помощью прямого поля в этом классе.

0 голосов
/ 25 мая 2018

Поскольку я теперь понял, как это сделать с помощью var s, вот ответ для точного интерфейса из вашего вопроса.

class ConfigurableRepo(
        private var _name: String,
        private var _pattern: String,
        private var _url: String) : Repository 
{
    override val name get () = _name

    override val pattern get () = _pattern

    override var url
        get () = _url
        set (u: String) { _url = u }
}
0 голосов
/ 25 мая 2018

Используйте абстрактный класс как это:

abstract class Repository {
    open val name = "default"
    open val pattern = "default"
    open val url = "default"
}

// example: only override name
class RepoWithDifferentName(
    override val name: String
): Repository() {
   // ...
}
0 голосов
/ 25 мая 2018

Пожалуйста, посмотрите на https://kotlinlang.org/docs/reference/visibility-modifiers.html

Особенно на 2-й абзац о классах и интерфейсах.

Из этих примеров можно было бы предложить, если это возможно в вашем случае, использоватьбазовый класс вместо интерфейса.Это будет выглядеть примерно так:

   open class DefaultRepo {
        protected open val name = "foo/bar/baz"
        protected open val pattern = "foo/bar/baz"
        protected open val url = "http://mycompanyrepo.com/$name"

        open fun add() {
            TODO("do something interesting here")
        }
    }

    class RenamedRepo(newName: String): DefaultRepo() {
        override val name = newName
    }

    class ConfigurableRepo(n: String, p: String, u: String): DefaultRepo() {
        override val name = n
        override val pattern = p
        override val url = u

        override fun add() {

        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...