1.委托模式
委托模式是软件设计模式中的一项基本技巧。简单来说,委托就是接收请求的一方将实现委托给了另一方,在Kotlin的语法结构中,使用by关键字可以直接支持委托模式,不需要编写样板代码。by关键字可以用在类和属性当中,分别表示类委托和属性委托。
2.类委托
先看一个java中使用委托模式的例子:
interface Printer {
void printSomething(String something);
}
static class PrinterDelegate implements Printer {
@Override
public void printSomething(String something) {
System.out.println("print from Delegate:" + something);
}
}
static class PrintingHouse implements Printer {
Printer mPrinter;
public PrintingHouse(Printer printer) {
mPrinter = printer;
}
@Override
public void printSomething(String something) {
mPrinter.printSomething(something);
}
}
public static void main(String[] args) {
PrinterDelegate delegate = new PrinterDelegate();
PrintingHouse printingHouse = new PrintingHouse(delegate);
printingHouse.printSomething("newspaper");
}
//输出结果
//print from Delegate:newspaper
PrintingHouse实现了Printer接口,但PrintingHouse并没有具体实现printSomething的功能,而是委托给了PrinterDelegate去实现,接下来我们使用kotlin的方式去实现它:
interface Printer{
fun printSomething(something:String)
}
class PrinterDelegate : Printer{
override fun printSomething(something: String) {
println("print from Delegate : $something")
}
}
class PrintingHouse(printer:Printer) : Printer by printer
fun main(){
val delegate = PrinterDelegate()
val printingHouse = PrintingHouse(delegate)
printingHouse.printSomething("newspaper")
}
//输出结果
//print from Delegate:newspaper
```**
两个版本实现的功能相同,可以看到kotlin完成委托仅需要使用by**关键字,这种写法就是kotlin中的类委托,类委托的声明直接写在类声明表达式中,就像这样:
```kotlin
interface A
interface B
class C(a:A,b:B) : A by a,B by b
3.属性委托
属性委托指的是一个类的某个属性值不是在类中直接进行定义,而是委托给一个代理类,从而实现对该属性统一管理,语法如下:
val/var <属性名>: <类型> by <表达式>
by关键字之后的表达式就是委托, 属性的 get() 方法(以及set() 方法)将被委托给这个对象的 getValue() 和 setValue() 方法。受委托的对象需提供 getValue() 函数(对于 var属性,还需要 setValue() 函数)。
看下面一个例子,定义一个Student类,将name属性委托给NameDelegate :
class Student {
var name: String by NameDelegate()
}
class NameDelegate {
private var value: String = ""
operator fun getValue(thisRef: Student, property: KProperty<*>): String {
return if (value.isEmpty()) "unknown" else value
}
operator fun setValue(thisRef: Student, property: KProperty<*>, value: String) {
this.value = value.trim()
}
}
fun main() {
val xiaoMing = Student()
println(xiaoMing.name)
xiaoMing.name = " 小明 "
println(xiaoMing.name)
}
//输出结果
//unknown
//小明
虽然受委托的类没有要求实现任何接口,但如果不想每次手动的去写getVlaue()和setValue()方法,也可以去实现ReadWriteProperty接口:
class NameDelegate : ReadWriteProperty<Student, String> {
private var value: String = ""
override fun getValue(thisRef: Student, property: KProperty<*>): String {
return if (value.isEmpty()) "unknown" else value
}
override fun setValue(thisRef: Student, property: KProperty<*>, value: String) {
this.value = value.trim()
}
}
实际上,Kotlin 的标准库中已经内置了很多工厂方法来实现属性的委托,在Android开发过程中经常用到的lazy就是标准库中的委托,lazy() 是接受一个 lambda 并返回一个 Lazy 实例的函数。lazy表示延迟属性,其值只在首次访问时计算。
这是lazy的一个使用示例:
class MainActivity : AppCompatActivity() {
private val mDialog : Dialog by lazy {
AlertDialog.Builder(this)
.setTitle("I am title")
.setNegativeButton("confirm",null)
.create()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun showDialog(view: View) {
mDialog.show()
}
}
该示例中,点击Button展示一个对话框mDialog,mDialog只在使用的时候才进行初始化。
4.总结
使用委托很大的一个好处是可以节省很多样板代码的编写,例如,你可以通过代理类在Activity中完成Extra或者SharedPreference属性的初始化。委托还有更多的案例,详细请参考官方文档。
更多安卓知识体系,请关注公众号: