Могу ли я опустить методы интерфейса, которые я не использую в Котлине?

Что делать, если меня интересует только onSee и не заботятся о других событиях? Могу ли я, по крайней мере, опустить методы, которые не имеют возвращаемых значений?

interface EventHandler
{
    fun onSee()
    fun onHear()
    fun onSmell()
    fun onTouch()
    fun onAwake()
    fun onSleep()
}

fun addEventHandler(handler:EventHandler)
{

}

fun Main()
{
    addEventHandler(object:EventHandler
    {
        override fun onSee()
        {
            print("I see.")
        }
    })
}

Ответ 1

Конечно, вы можете реализовать только один метод интерфейса, все, что вам нужно сделать, - предоставить реализацию по умолчанию для других методов в объявлении интерфейса

interface EventHandler {
    fun onSee()
    fun onHear() { /* default implementation */ }
    fun onSmell(){ /* default implementation */ }
    fun onTouch(){ /* default implementation */ }
    fun onAwake(){ /* default implementation */ }
    fun onSleep(){ /* default implementation */ }
}

Теперь, когда вы создаете экземпляр этого интерфейса, вам нужно только обеспечить обязательную реализацию onSee(), остальные необязательны

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

interface OnSeeEventHandler: EventHandler {
    override fun onHear() { /* default implementation */ }
    override fun onSmell(){ /* default implementation */ }
    override fun onTouch(){ /* default implementation */ }
    override fun onAwake(){ /* default implementation */ }
    override fun onSleep(){ /* default implementation */ }
}

И использовать OnSeeEventHandler обеспечить только onSee метод imeplementation

Ответ 2

Я придумал следующий, несколько интересный подход.

Функция ниже использует динамический прокси для "материализации" интерфейса и исправления его только с помощью необходимых методов. Методы, которые не исправлены, будут возвращать null или Unit, в зависимости от типа возврата.

import java.lang.reflect.Proxy.newProxyInstance

inline fun <reified T> Any.materialize(): T = materialize(T::class.java, this)

fun <T> materialize(i: Class<T>, x: Any = object {}): T {
    @Suppress("UNCHECKED_CAST")
    return newProxyInstance(i.classLoader, arrayOf(i)) { _, m, args ->
        x.javaClass.methods
                .asSequence()
                .filter {
                    it.name == m.name
                            && it.parameterTypes!!.contentEquals(m.parameterTypes)
                }
                .map {
                    it.invoke(x, *args.orEmpty())
                }.firstOrNull()
    } as T
}

Затем он может использоваться следующим образом, учитывая интерфейс Foo и анонимный объект, который содержит только реализацию своей функции qux():

interface Foo {
    fun bar()
    fun baz(): String
    fun qux(s: String): String
}

fun main(vararg args: String) {
    val foo = object {
        fun qux(s: String): String {
            return "Returned from qux: $s"
        }
    }.materialize<Foo>()

    println(foo.bar()) // void no-op, prints "kotlin.Unit"
    println(foo.baz()) // no-op with return value, prints "null"
    println(foo.qux("Hello")) // prints "Returned from qux: Hello"

}

отказ

  • Используя это, вы теряете всю проверку времени компиляции, так как все разрешено во время выполнения.
  • Некоторые вещи не охватываются этой реализацией (например, методы по умолчанию для интерфейса).
  • Производительность вообще не учитывается.
  • Требуется зависимость от kotlin-reflect.
  • Сегодня мой второй день обучения Kotlin, так что может быть любое количество необрезанных случаев края и ошибок.

Я бы не использовал это сам в большинстве случаев и продолжу придерживаться конструкции Kotlin, которая поддерживает частичные реализации интерфейса (например, TypeScript Partial<T>).

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