Можно ли указать статическую функцию в интерфейсе Kotlin?

Я хочу сделать что-то вроде этого:

interface Serializable<FromType, ToType> {
    fun serialize(): ToType
    companion object {
        abstract fun deserialize(serialized: ToType): FromType
    }
}

или даже это будет работать для меня:

interface Serializable<ToType> {
    fun serialize(): ToType
    constructor(serialized: ToType)
}

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

3 ответа

Решение

В принципе, ничего в companion object может быть abstract или же open (и таким образом быть переопределенным), и нет никакого способа требовать реализации ' companion object s иметь метод или определять / требовать конструктор в интерфейсе.

Возможное решение для вас - разделить эти две функции на два интерфейса:

interface Serializable<ToType> {
    fun serialize(): ToType
}

interface Deserializer<FromType, ToType> {
    fun deserialize(serialized: ToType): FromType
}

Таким образом, вы сможете реализовать первый интерфейс в классе и сделать его companion object реализовать другой:

class C: Serializable<String> {
    override fun serialize(): String = "..."

    companion object : Deserializer<C, String> {
        override fun deserialize(serialized: String): C = C()
    }
}

Кроме того, существует серьезное ограничение, заключающееся в том, что в качестве супертипа может использоваться только одна общая специализация типа, поэтому такая модель сериализации через реализацию интерфейса может оказаться недостаточно масштабируемой, что не позволяет использовать несколько реализаций с разными ToType s.

Для будущего использования также можно передать дочерний класс функции в качестве параметра получателя:

      val encodableClass = EncodableClass("Some Value")
//The encode function is accessed like a member function on an instance
val stringRepresentation = encodableClass.encode()
//The decode function is accessed statically
val decodedClass = EncodableClass.decode(stringRepresentation)

interface Encodable<T> {
    fun T.encode(): String
    fun decode(stringRepresentation: String): T
}

class EncodableClass(private val someValue: String) {
    // This is the remaining awkwardness, 
    // you have to give the containing class as a Type Parameter 
    // to its own Companion Object
    companion object : Encodable<EncodableClass> {
        override fun EncodableClass.encode(): String {
            //You can access (private) fields here
            return "This is a string representation of the class with value: $someValue"
        }
        override fun decode(stringRepresentation: String): EncodableClass {
            return EncodableClass(stringRepresentation)
        }
    }
}


//You also have to import the encode function separately: 
// import codingProtocol.EncodableClass.Companion.encode

Для меня это более оптимальный вариант использования. Вместо одной функции в объекте-экземпляре и другой в объекте-компаньоне, как в вашем примере, мы перемещаем обе функции в объект-компаньон и расширяем экземпляр.

Я относительно новичок в Kotlin. Вот мои 2¢

  1. сопутствующий объект является экземпляром класса и как таковой не может быть унаследован от. Вот почему абстрактной функции не будет места для реализации. В Java для аналогичного результата требуется анонимный класс, реализующий абстрактный класс, но он сильно отличается от переопределяющего метода для экземпляра класса.

  2. Интерфейс нельзя использовать для создания экземпляра, поэтому в интерфейсе нет использования конструктора.

Почему бы вам не создать общий абстрактный класс? Тогда абстрактная или открытая функция будет работать для функций serialize(): ToType и deserialize(serialized: ToType): FromType.

Другие вопросы по тегам