Kotlin 简明教程

Kotlin - Delegation

Kotlin 通过引入新关键字 “by” 来支持 “delegation” 设计模式。使用此关键字或委派方法,Kotlin 允许派生类通过特定对象访问接口的所有已实现的公共方法。以下示例演示了如何在 Kotlin 中实现此目的。

Kotlin supports “delegation” design pattern by introducing a new keyword “by”. Using this keyword or delegation methodology, Kotlin allows the derived class to access all the implemented public methods of an interface through a specific object. The following example demonstrates how this happens in Kotlin.

interface Base {
   fun printMe() //abstract method
}
class BaseImpl(val x: Int) : Base {
   override fun printMe() { println(x) }   //implementation of the method
}
class Derived(b: Base) : Base by b  // delegating the public method on the object b

fun main(args: Array<String>) {
   val b = BaseImpl(10)
   Derived(b).printMe() // prints 10 :: accessing the printMe() method
}

在这个示例中,我们有一个名为“Base”的接口,其抽象方法名为“printme()”。在 BaseImpl 类中,我们正在实现这个“printme()”,然后在另一个类中,我们使用“by”关键字使用这个实现。

In the example, we have one interface “Base” with its abstract method named “printme()”. In the BaseImpl class, we are implementing this “printme()” and later from another class we are using this implementation using “by” keyword.

以上代码段将在浏览器中产生以下输出。

The above piece of code will yield the following output in the browser.

10

Property Delegation

在上一节中,我们已经学习了如何使用“by”关键字委派设计模式。在本节中,我们将学习如何使用 Kotlin 库中提到的某些标准方法委派属性。

In the previous section, we have learned about the delegation design pattern using “by” keyword. In this section, we will learn about delegation of properties using some standard methods mentioned in Kotlin library.

委派是指将责任传递给另一个类或方法。当某个属性已经在某些地方声明时,我们应重复使用同一代码来初始化它们。在下面的示例中,我们将使用 Kotlin 提供的一些标准委派方法和在示例中实现委派时的一些标准库函数。

Delegation means passing the responsibility to another class or method. When a property is already declared in some places, then we should reuse the same code to initialize them. In the following examples, we will use some standard delegation methodology provided by Kotlin and some standard library function while implementing delegation in our examples.

Using Lazy()

Lazy 是一个 lambda 函数,它将一个属性作为输入,并返回一个 Lazy<T> 实例,其中 <T> 是它使用的属性的基本类型。我们看一下以下内容来理解它是如何工作的。

Lazy is a lambda function which takes a property as an input and in return gives an instance of Lazy<T>, where <T> is basically the type of the properties it is using. Let us take a look at the following to understand how it works.

val myVar: String by lazy {
   "Hello"
}
fun main(args: Array<String>) {
   println(myVar +" My dear friend")
}

在上面的代码片段中,我们向 Lazy 函数传递一个变量“myVar”,它反过来将值分配给其对象,并将其返回给主函数。以下是浏览器的输出。

In the above piece of code, we are passing a variable “myVar” to the Lazy function, which in return assigns the value to its object and returns the same to the main function. Following is the output in the browser.

Hello My dear friend

Delegetion.Observable()

Observable() 采用两个参数来初始化对象,并将同一对象返回给被调用函数。在下面的示例中,我们将看到如何使用 Observable() 方法来实现委派。

Observable() takes two arguments to initialize the object and returns the same to the called function. In the following example, we will see how to use Observable() method in order to implement delegation.

import kotlin.properties.Delegates
class User {
   var name: String by Delegates.observable("Welcome to Tutorialspoint.com") {
      prop, old, new ->
      println("$old -> $new")
   }
}
fun main(args: Array<String>) {
   val user = User()
   user.name = "first"
   user.name = "second"
}

以上代码段将在浏览器中产生以下输出。

The above piece of code will yield the following output in the browser.

first -> second

通常,语法就是“by”关键字之后的表达式被委派。变量 pget()set() 方法将被委派到其在 Delegate 类中定义的 getValue()setValue() 方法。

In general, the syntax is the expression after the “by” keyword is delegated. The get() and set() methods of the variable p will be delegated to its getValue() and setValue() methods defined in the Delegate class.

class Example {
   var p: String by Delegate()
}

对于上面的代码片段,以下是我们为在变量 p 中分配值而需要生成的委派类。

For the above piece of code, following is the delegate class that we need to generate in order to assign the value in the variable p.

class Delegate {
   operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
      return "$thisRef, thank you for delegating '${property.name}' to me!"
   }
   operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
      println("$value has been assigned to '${property.name} in $thisRef.'")
   }
}

读取时,将调用 getValue() 方法;设置变量时,将调用 setValue() 方法。

While reading, getValue() method will be called and while setting the variable setValue() method will be called.