7.12.1 代理模式(Proxy Pattern)
代理模式,也称委托模式。
在代理模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。代理模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在特殊的场合采用了代理模式。代理模式使得我们可以用聚合来替代继承,它还使我们可以模拟mixin(混合类型)。委托模式的作用是将委托者与实际实现代码分离出来,以达成解耦的目的。
一个代理模式的Java代码示例:
package com.easy.kotlin;
interface JSubject {
public void request();
}
class JRealSubject implements JSubject {
@Override
public void request() {
System.out.println("JRealSubject Requesting");
}
}
class JProxy implements JSubject {
private JSubject subject = null;
//通过构造函数传递代理者
public JProxy(JSubject sub) {
this.subject = sub;
}
@Override
public void request() { //实现接口中定义的方法
this.before();
this.subject.request();
this.after();
}
private void before() {
System.out.println("JProxy Before Requesting ");
}
private void after() {
System.out.println("JProxy After Requesting ");
}
}
public class DelegateDemo {
public static void main(String[] args) {
JRealSubject jRealSubject = new JRealSubject();
JProxy jProxy = new JProxy(jRealSubject);
jProxy.request();
}
}
输出:
JProxy Before Requesting
JRealSubject Requesting
JProxy After Requesting
```### 7.13.2 类的委托(Class Delegation)
就像支持单例模式的object对象一样,Kotlin 在语言层面原生支持委托模式。
代码示例:
```kotlin
package com.easy.kotlin
import java.util.*
interface Subject {
fun hello()
}
class RealSubject(val name: String) : Subject {
override fun hello() {
val now = Date()
println("Hello, REAL $name! Now is $now")
}
}
class ProxySubject(val sb: Subject) : Subject by sb {
override fun hello() {
println("Before ! Now is ${Date()}")
sb.hello()
println("After ! Now is ${Date()}")
}
}
fun main(args: Array<String>) {
val subject = RealSubject("World")
subject.hello()
println("-------------------------")
val proxySubject = ProxySubject(subject)
proxySubject.hello()
}
在这个例子中,委托代理类 ProxySubject 继承接口 Subject,并将其所有共有的方法委托给一个指定的对象sb :
class ProxySubject(val sb: Subject) : Subject by sb
ProxySubject 的超类型Subject中的 by sb 表示 sb 将会在 ProxySubject 中内部存储。另外,我们在覆盖重写了函数override fun hello()。
测试代码:
fun main(args: Array<String>) {
val subject = RealSubject("World")
subject.hello()
println("-------------------------")
val proxySubject = ProxySubject(subject)
proxySubject.hello()
}
输出:
Hello, REAL World! Now is Wed Jul 05 02:45:42 CST 2017
-------------------------
Before ! Now is Wed Jul 05 02:45:42 CST 2017
Hello, REAL World! Now is Wed Jul 05 02:45:42 CST 2017
After ! Now is Wed Jul 05 02:45:42 CST 2017
7.12.3 委托属性 (Delegated Properties)
通常对于属性类型,我们是在每次需要的时候手动声明它们:
class NormalPropertiesDemo {
var content: String = "NormalProperties init content"
}
那么这个content属性将会很“呆板”。属性委托赋予了属性富有变化的活力。
例如:
延迟属性(lazy properties): 其值只在首次访问时计算
可观察属性(observable properties): 监听器会收到有关此属性变更的通知
把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中。
委托属性
Kotlin 支持 委托属性:
class DelegatePropertiesDemo {
var content: String by Content()
override fun toString(): String {
return "DelegatePropertiesDemo Class"
}
}
class Content {
operator fun getValue(delegatePropertiesDemo: DelegatePropertiesDemo, property: KProperty<*>): String {
return "${delegatePropertiesDemo} property '${property.name}' = 'Balalala ... ' "
}
operator fun setValue(delegatePropertiesDemo: DelegatePropertiesDemo, property: KProperty<*>, value: String) {
println("${delegatePropertiesDemo} property '${property.name}' is setting value: '$value'")
}
}
在 var content: String by Content()中, by 后面的表达式的Content()就是该属性委托的对象。content属性对应的 get()(和 set())会被委托给Content()的 operator fun getValue() 和 operator fun setValue() 函数,这两个函数是必须的,而且得是操作符函数。
测试代码:
val n = NormalPropertiesDemo()
println(n.content)
n.content = "Lao tze"
println(n.content)
val e = DelegatePropertiesDemo()
println(e.content) // call Content.getValue
e.content = "Confucius" // call Content.setValue
println(e.content) // call Content.getValue
输出:
NormalProperties init content
Lao tze
DelegatePropertiesDemo Class property 'content' = 'Balalala ... '
DelegatePropertiesDemo Class property 'content' is setting value: 'Confucius'
DelegatePropertiesDemo Class property 'content' = 'Balalala ...
懒加载属性委托 lazy
lazy() 函数定义如下:
@kotlin.jvm.JvmVersion
public fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
它接受一个 lambda 并返回一个 Lazy <T> 实例的函数,返回的实例可以作为实现懒加载属性的委托:第一次调用 get() 会执行已传递给 lazy() 的 lamda 表达式并记录下结果, 后续调用 get() 只是返回之前记录的结果。
代码示例:
val synchronizedLazyImpl = lazy({
println("lazyValueSynchronized1 3!")
println("lazyValueSynchronized1 2!")
println("lazyValueSynchronized1 1!")
"Hello, lazyValueSynchronized1 ! "
})
val lazyValueSynchronized1: String by synchronizedLazyImpl
println(lazyValueSynchronized1)
println(lazyValueSynchronized1)
val lazyValueSynchronized2: String by lazy {
println("lazyValueSynchronized2 3!")
println("lazyValueSynchronized2 2!")
println("lazyValueSynchronized2 1!")
"Hello, lazyValueSynchronized2 ! "
}
println(lazyValueSynchronized2)
println(lazyValueSynchronized2)
输出:
lazyValueSynchronized1 3!
lazyValueSynchronized1 2!
lazyValueSynchronized1 1!
Hello, lazyValueSynchronized1 !
Hello, lazyValueSynchronized1 !
lazyValueSynchronized2 3!
lazyValueSynchronized2 2!
lazyValueSynchronized2 1!
Hello, lazyValueSynchronized2 !
Hello, lazyValueSynchronized2 !
默认情况下,对于 lazy 属性的求值是同步的(synchronized), 下面两种写法是等价的:
val synchronizedLazyImpl = lazy({
println("lazyValueSynchronized1 3!")
println("lazyValueSynchronized1 2!")
println("lazyValueSynchronized1 1!")
"Hello, lazyValueSynchronized1 ! "
})
val synchronizedLazyImpl2 = lazy(LazyThreadSafetyMode.SYNCHRONIZED, {
println("lazyValueSynchronized1 3!")
println("lazyValueSynchronized1 2!")
println("lazyValueSynchronized1 1!")
"Hello, lazyValueSynchronized1 ! "
})
该值是线程安全的。所有线程会看到相同的值。如果初始化委托多个线程可以同时执行,不需要同步锁,使用LazyThreadSafetyMode.PUBLICATION:
val lazyValuePublication: String by lazy(LazyThreadSafetyMode.PUBLICATION, {
println("lazyValuePublication 3!")
println("lazyValuePublication 2!")
println("lazyValuePublication 1!")
"Hello, lazyValuePublication ! "
})
而如果属性的初始化是单线程的,那么我们使用 LazyThreadSafetyMode.NONE 模式(性能最高):
val lazyValueNone: String by lazy(LazyThreadSafetyMode.NONE, {
println("lazyValueNone 3!")
println("lazyValueNone 2!")
println("lazyValueNone 1!")
"Hello, lazyValueNone ! "
})
Delegates.observable 可观察属性委托
我们把属性委托给Delegates.observable函数,当属性值被重新赋值的时候, 触发其中的回调函数 onChange。
该函数定义如下:
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
代码示例:
class PostHierarchy {
var level: String by Delegates.observable("P0",
{ property: KProperty<*>,
oldValue: String,
newValue: String ->
println("$oldValue -> $newValue")
})
}
测试代码:
val ph = PostHierarchy()
ph.level = "P1"
ph.level = "P2"
ph.level = "P3"
println(ph.level) // P3
输出:
P0 -> P1
P1 -> P2
P2 -> P3
P3
我们可以看出,属性level每次赋值,都回调了Delegates.observable中的lambda表达式所写的onChange函数。
Delegates.vetoable 可否决属性委托
这个函数定义如下:
public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
}
当我们把属性委托给这个函数时,我们可以通过onChange函数的返回值是否为true, 来选择属性的值是否需要改变。
代码示例:
class PostHierarchy {
var grade: String by Delegates.vetoable("T0", {
property, oldValue, newValue ->
true
})
var notChangeGrade: String by Delegates.vetoable("T0", {
property, oldValue, newValue ->
false
})
}
测试代码:
ph.grade = "T1"
ph.grade = "T2"
ph.grade = "T3"
println(ph.grade) // T3
ph.notChangeGrade = "T1"
ph.notChangeGrade = "T2"
ph.notChangeGrade = "T3"
println(ph.notChangeGrade) // T0
我们可以看出,当onChange函数返回值是false的时候,对属性notChangeGrade的赋值都没有生效,依然是原来的默认值T0 。
Delegates.notNull 非空属性委托
我们也可以使用委托来实现属性的非空限制:
var name: String by Delegates.notNull()
这样name属性就被限制为不能为null,如果被赋值null,编译器直接报错:
ph.name = null // error
Null can not be a value of a non-null type String
属性委托给Map映射
我们也可以把属性委托给Map:
class Account(val map: Map<String, Any?>) {
val name: String by map
val password: String by map
}
测试代码:
val account = Account(mapOf(
"name" to "admin",
"password" to "admin"
))
println("Account(name=${account.name}, password = ${account.password})")
输出:
Account(name=admin, password = admin)
如果是可变属性,这里也可以把只读的 Map 换成 MutableMap :
class MutableAccount(val map: MutableMap<String, Any?>) {
var name: String by map
var password: String by map
}
测试代码:
val maccount = MutableAccount(mutableMapOf(
"name" to "admin",
"password" to "admin"
))
maccount.password = "root"
println("MutableAccount(name=${maccount.name}, password = ${maccount.password})")
输出:
MutableAccount(name=admin, password = root)