Могу ли я опустить методы интерфейса, которые я не использую в Котлине?
Что делать, если меня интересует только 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>
).
Я только предлагаю этот подход, потому что это может представлять интерес для некоторых случаев использования, и я сожалею, если это заставило ваши глаза кровоточить.