专栏首页一个会写诗的程序员的博客Kotlin 中的接口 Interface : so much betterKotlin 开发者社区

Kotlin 中的接口 Interface : so much betterKotlin 开发者社区

Interface was introduced in Java as a new programming feature. It describes CAN-BE instead of IS-A relationship. That also enables it to perform multiple inheritance (e.g. something can be many things, but only is a thing).

However as we know even up to Java 7 (which once was the main language for native Android Development), Interface does have various drawbacks, making it not as attractive, and at times, some have to resort back to abstract class.

With Kotlin in place, let me share with you how Kotlin made Inheritance better.

Kotlin made Interface extensible. In Java 7, inheritance function declaration can’t have implementation. Hence those class implements an interface, need to have all it’s function implemented.

This is a problem, as this makes interface inextensible.

Imagine we have the below Movable interface.

interface Movable { int legsCount(); } class Horse implements Movable { @Override public int legsCount() { return 4; } } Then we realize that other than legs, we need to count wings too. So we add wingsCount().

It is unfortunate those that implemented this interface i.e. Horse will also need to change.

interface Movable { int legsCount(); int wingsCount(); } class Horse implements Movable { @Override public int legsCount() { return 4; } @Override public int wingsCount() { return 0; } } In Kotlin We initially have

interface Movable { fun legsCount(): Int } class Horse : Movable { override fun legsCount() = 4 } Then we could easily extend it.

interface Movable { fun legsCount(): Int fun wingsCount(): Int { return 0 } } class Horse : Movable { override fun legsCount() = 4 } Or even more, without need to modify Horse class at all!

interface Movable { fun legsCount(): Int { return 0 } fun wingsCount(): Int { return 0 } fun canFly(): Boolean { return wingsCount() > 1 } fun canWalk(): Boolean { return legsCount() > 1 } } class Horse : Movable { override fun legsCount() = 4 } Kotlin made Interface truly override. The definition of override according to Cambridge Dictionary is

to decide against or refuse to accept a previous decision, an order, a person, etc. In the Java world, Interface is overriding nothing.

But in Kotlin world, look at the example below

interface Movable { fun legsCount(): Int { return 0 } fun wingsCount(): Int { return 0 } fun canFly(): Boolean { return wingsCount() > 1 } fun canWalk(): Boolean { return legsCount() > 1 } } class Horse : Movable { var isSick = false override fun legsCount() = 4 override fun canWalk(): Boolean { if (isSick) { return false } return super.canWalk() } } If we set horse.isSick = true, the canWalk() function will return false, regardless of the leg counts. A truly overriding capability.

Kotlin made Interface more object like In Java world (I believe including Java 8 and 9), Interface are not allowed to have property other than final constant variable (hmm… constant variable sounds oxymoron, perhaps should be called constant value).

At most we could make an accessor function e.g. legCount().

In Kotlin With Kotlin, one could have a property in Interface.

Instead of writing

interface Movable { fun legsCount(): Int fun canWalk() = legsCount() > 1 } class Horse : Movable { override fun legsCount() = 4 } One could write as

interface Movable { val legsCount : Int fun canWalk(): Boolean = legsCount > 1 } class Horse : Movable { override val legsCount = 4 } There’s some limitation for the property in Interface though, as it can’t have backfield property, which means it can’t be change. So it is still stateless. Besides, it also can’t be initialized in the interface itself. Kotlin made Interface a better composition You might have heard Composition over Inheritance principle. Kotlin made this even more simpler

Imagine you have Horse and Dog. Both are 4 legs animal.

One way to program is as below

interface Movable { val legsCount : Int fun canWalk() = legsCount > 1 } class Horse : Movable { override val legsCount = 4 } class Dog : Movable { override val legsCount = 4 } This is so cumbersome as we have to

replicate the code override val legsCount = 4 for each of them.

If we have more functions to override, or more class object that is 4 legs animal, we’ll have to do the same.

If one day we change to 4 to “four”, or add more functionality…

It would be a nightmare to change . So inextensible.

We can make an class inheritance of that perhaps? interface Movable { val legsCount: Int fun canWalk() = legsCount > 1 } open class FourLegged : Movable { override val legsCount = 4 } class Horse : FourLegged() class Dog : FourLegged() But this violates the Composition over Inheritance principle. Horse and Dogare not only FourLegged, but could be something else, making them very inextensible to other type anymore (e.g. Pet).

This is also inextensible ☹️

So let’s apply Composite over Inheritance (the traditional way) interface Movable { val legsCount: Int fun canWalk() = legsCount > 1 } object FourLegged : Movable { override val legsCount = 4 } class Horse : Movable { private val movable = FourLegged override val legsCount get() = movable.legsCount } class Dog : Movable { private val movable = FourLegged override val legsCount get() = movable.legsCount } I don’t know about you, I dislike this equally, So let’s enhance it better to as below…

interface Movable { val legsCount: Int fun canWalk() = legsCount > 1 } object FourLegged : Movable { override val legsCount = 4 } open class MovableImpl(private val movable: Movable) : Movable { override val legsCount get() = movable.legsCount } class Horse : MovableImpl(FourLegged) class Dog : MovableImpl(FourLegged) Now this is better, as it is more extensible, as in the future we have FourLegged or TwoLegged etc, we could easily add to it.

But I still dislike it, as I need to have the intermediate class MovableImpl. So let’s check out further what how Kotlin could made our interface better…

The Kotlin provided way: By … delegate to composition made easy With the interface in Kotlin, we could use the By keyword to generate the Delegate pattern so easily. Check it out

interface Movable { val legsCount: Int fun canWalk() = legsCount > 1 } object FourLegged : Movable { override val legsCount = 4 } class Horse : Movable by FourLegged class Dog : Movable by FourLegged So much nicer! ?. Hopes you see how good that is.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Integer 与 Long 数字类型的比较:Java与Kotlin的细节不同

    我们在数学中,123 == 123 , 直觉上是一目了然的。但是到了计算机编程语言中, 问题就显得有点“傻瓜”化了。

    一个会写诗的程序员
  • 《Kotlin 程序设计》第五章 Kotlin 面向对象编程(OOP)第五章 Kotlin 面向对象编程(OOP)1. 面向对象的HelloWorld 2. 面向对象编程思想简述3.Kotlin 面向

    Kotlin 同Java、 Scala、Groovy 一样,都使用关键字class 来定义类。

    一个会写诗的程序员
  • 《Kotlin 程序设计》第十二章 Kotlin的多线程

    Kotlin 1.1 introduced coroutines, a new way of writing asynchronous, non-blockin...

    一个会写诗的程序员
  • 内存管理篇(三):Go垃圾回收之三色标记算法

    三色标记法(tricolor mark-and-sweep algorithm)是传统 Mark-Sweep 的一个改进,它是一个并发的 GC 算法,在Gola...

    灰子学技术
  • ios内存管理机制

    iOS内存管理机制的原理是引用计数,当这块内存被创建后,它的引用计数+1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时候有另外一个对象或指针...

    赵哥窟
  • logstash 重复消费kafka问题

    前两天业务方突然找到我说当天索引ES查询很慢,原来毫秒级的查询现在竟然要20s,让我处理下。我看了下索引大小,原来是1分片6g左右,今天突然就变成了1分片32g...

    YG
  • ​LeetCode 739:每日温度 Daily Temperatures

    根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。

    爱写bug
  • 行业视角 | Gartner报告指出数据库技术发展方向

    自Gartner发布数据库行业报告((Other Vendors to Consider for Operational DBMSs 2017))以来,第一次收...

    加米谷大数据
  • codeforces 1396A(构造)

    dejavu1zz
  • 干货:分布式系统学习笔记

    比如海量数据,单机存储不下,需要多机,以集群的方式存储,即为数据的分布式存储,数据存储的分布式一般涉及如下几个方面

    技术zhai

扫码关注云+社区

领取腾讯云代金券