本文链接
本文结合自己的感受,做一下简单的翻译。原文作者也是《Kotlin for Android developer》的作者。此译文供大家学习参考之用。
Kotlin中的接口,谁说接口不能有实现代码
相比Java,用Kotlin写的接口允许你复用更多代码。理由很简单:你可以加实现代码到接口中。如果你在Java8中尝试,也是类似的。在接口中加实现代码是一件不错的事情,这是你能使用更多强大的代码组合方式。然后我们接下去看看。
Java 6中的接口
Java接口的问题是我们只能定义描述行为,但是不能有实现。很多的时候,这够了,但是如果我们要达到更好的组合方式,由于强制我们把接口的实现委托给实现对象,这些情况不能解决。这样使得本来简单组合一下可重用代码片段就能解决的问题,变的复杂化了。
Kotlin中使用接口
Kotlin带给我们一些好消息:接口可以有实现代码。这个意味着我们能实现一种类的多重继承(有些例子中有部分限制)。我们能让一个类实现几个接口,从每个接口继承行为(有实现代码)。(Java中的类不能多重继承类,这是一个很大的限制)
写一些有方法实现的接口,你不需要做任何特别的:
interface Interface1 {
fun function1() {
Log.d("Interface1", "function1 called")
}
}
我们有另外一个接口2实现了其他方法:
interface Interface2 {
fun function2() {
Log.d("Interface2", "function2 called")
}
}
有一个类都实现了他们没有问题:
class MyClass : Interface1, Interface2 {
fun myFunction() {
function1()
function2()
}
}
好,当组织我们代码的时候,这给我们更多的多样性。
接口不能持有状态
这在思考代码时候有一个重要的限制。我们能有实现代码但是没有状态。这意味着我们不能创建一个属性,然后用它存储状态。如果我们在接口中定义了一个属性,这个类实现了它就必须重写这个属性。(你可以定义这个属性在接口中,但是实现类必须重写,本质是定义一个该属性的get方法)
让我们看一个例子。想象一下这个接口需要上下文:
interface Toaster {
val context: Context
fun toast(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
这个代码很简单。这个接口有一个实现的方法用来显示一个Toast。 它需要一个上下文来做这些事情。如果我们有一个Activity要用这个接口,需要重写这个上下文:
class MyActivity : AppCompatActivity(), Toaster {
override val context = this
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
toast("onCreate")
}
}
简单的,我们设置这个Activity 自己作为上下文,这个接口就使用它。 现在你可以在这个Activity 使用Toaster 函数没有任何问题。
接口委托
在Kotlin中另外的非常有趣的特性是接口委托。这个是非常强大的工具让你能实现一个更干净的代码组合。想象你有一个类C,组合了类A和B的2个对象:
interface A {
fun functionA(){}
}
interface B {
fun functionB(){}
}
class C(val a: A, val b: B) {
fun functionC(){
a.functionA()
b.functionB()
}
}
类C在自己代码中使用A和B的函数。如果一个对象是组合自它们的组件,那它就可以直接的使用它们的函数。
使用接口委托是另外一种写法,结果和上面一样的方式:
class C(a: A, b: B): A by a, B by b {
fun functionC(){
functionA()
functionB()
}
}
你能看到类C实现了A和B,但是它接受作为参数,对象全部委托实现(个人理解是一个继承转化为组合的方式)。使用接口委托,这个类能直接使用被实现类的函数,并且包括使用其他对象委托实现。
总结
我们看到了Java和Kotlin接口的不同之处。现在试着找出简单的解决方式,这些新的方式打开了许多世界的可能。你们的代码会比之前有更多的复用性,以及更好的可读性。