刚好在复习重温Kotlin官方文档,本来想着写点高级函数啥的,但是看到委托模式就忍不住想和Java做对比,先写着记下来吧,记得之前看到过一篇讲Kotlin的协变逆变的文章,与Java的泛型上下限很类似,有空找找看再写。
简单的Java静态代理
总共有4个类,IPersion
是通用接口,Student
是IPersion
的一个实现类,StudentProxy
也是IPersion
的一个实现类,同时StudentProxy
持有IPersion
接口对象,在实现接口方法的时候调用接口对象的相应方法实现了对具体类的代理处理,在代理类中可以进行一些通用操作,如在每个方法执行前后记录日志什么的。但是一个代理类只能代理一种类型的对象显然胜任不了复杂项目,于是乎动态代理就出现了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57package DerivedModel;
/**
* describe: Java的简单静态代理
* author: kaithmy
* date: 2018/8/13 15:46
**/
public class StaticDerived {
public static void main(String[] args) {
StudentProxy studentProxy = new StudentProxy(new Student("小明"));
studentProxy.say();
studentProxy.eat();
}
}
interface IPersion {
void say();
void eat();
}
class Student implements IPersion {
private String name;
public Student(String name) {
this.name = name;
}
public void say() {
System.out.println("My name is " + name + ",and I'm a student.");
}
public void eat() {
System.out.println("My name is " + name + ",and I'm eating now.");
}
}
class StudentProxy implements IPersion {
private IPersion iPersion;
public StudentProxy(IPersion iPersion) {
this.iPersion = iPersion;
}
public void say() {
iPersion.say();
}
public void eat() {
iPersion.eat();
}
}
JDK动态代理
与静态代理相比,我们保留了Student
和IPersion
,并且新增了具体方法执行者DynamicHandler
,新增了获取被代理对象的工厂类DynamicFactory
。熟悉反射的同学一眼就看出来DynamicFactory
通过反射获取被代理对象,通过DynamicHandler
调用对应的反射方法,是的没错,确实如此,由于DynamicHandler
是具体方法的调用类,所以一些通用操作可以放在method.invoke()
方法执行前后。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64package DerivedModel;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* describe: JDK 动态代理简单实现
* author: kaithmy
* date: 2018/8/13 16:25
**/
public class DynamicDerived {
public static void main(String[] args) {
IPersion xiaohong = (IPersion) DynamicFactory.getProxy(new Student("小红"));
xiaohong.eat();
xiaohong.say();
}
}
interface IPersion {
void say();
void eat();
}
class Student implements IPersion {
private String name;
public Student(String name) {
this.name = name;
}
public void say() {
System.out.println("My name is " + name + ",and I'm a student.");
}
public void eat() {
System.out.println("My name is " + name + ",and I'm eating now.");
}
}
class DynamicHandler implements InvocationHandler {
private Object object;
public DynamicHandler(Object object) {
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(object, args);
}
}
class DynamicFactory {
public static Object getProxy(Object object) {
DynamicHandler dynamicHandler = new DynamicHandler(object);
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces()
, dynamicHandler);
}
}
cglib动态代理
cglib代理和JDK动态代理很类似,只不过cglib依赖了ASM快速生成被代理对象的字节码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61package DerivedModel;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* describe: cglib动态代理简单实现
* author: kaithmy
* date: 2018/8/13 16:45
**/
public class CglibDynamicDerived {
public static void main(String[] args) {
Student xiaoli = (Student) new CGlibProxy().GetInstance(new Student("小李"));
xiaoli.say();
xiaoli.eat();
}
}
interface IPersion {
void say();
void eat();
}
class Student implements IPersion {
private String name;
public Student(String name) {
this.name = name;
}
public void say() {
System.out.println("My name is " + name + ",and I'm a student.");
}
public void eat() {
System.out.println("My name is " + name + ",and I'm eating now.");
}
}
class CGlibProxy implements MethodInterceptor {
private Object object;
public Object GetInstance(Object object) {
this.object = object;
Enhancer enhancer = new Enhancer();//增强器
enhancer.setSuperclass(object.getClass());//指定代理类
enhancer.setCallback(this);//所有代理类方法均会回调,使用intercept()拦截
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invoke(o, objects);
}
}
Kotlin的静态代理-委托模式
委托模式已经证明是实现继承的一个很好的替代方式, 而 Kotlin 可以零样板代码地原生支持它。下面DerivedProxy
的超类型列表中的 by
-子句表示person
将会在DerivedProxy
中内部存储, 并且编译器将生成转发给person
的所有IPersion
的方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29package DerivedModel
/**
* describe: Kotlin的静态代理-委托模式
* author: kaithmy
* date: 2018/8/13 17:09
**/
fun main(args: Array<String>) {
val teacher = Teacher("邹小雨")
DerivedProxy(teacher).eat()
DerivedProxy(teacher).sleep()
}
interface IPerson {
fun eat()
fun sleep()
}
class Teacher(var name: String) : IPerson {
override fun eat() {
println("My name is $name ,I'm eating")
}
override fun sleep() {
println("My name is $name ,I'm sleeping")
}
}
class DerivedProxy(person: IPerson) : IPerson by person
执行结果如下:1
2My name is 邹小雨 ,I'm eating
My name is 邹小雨 ,I'm sleeping
如果在代理类中重写了对应被代理类的属性和方法呢?我们试试1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49package DerivedModel
/**
* describe: Kotlin的静态代理-委托模式
* author: kaithmy
* date: 2018/8/13 17:09
**/
fun main(args: Array<String>) {
val teacher = Teacher("邹小雨")
//由于eat()方法被重写,故调用的是代理类对象的eat()
DerivedProxy(teacher).eat()
//由于sleep()方法没有被重写,故调用的是被代理类对象的sleep()
DerivedProxy(teacher).sleep()
//由于print()方法没有被重写,故调用的是被代理类对象的print(),由此只能访问被代理类的对象的属性
DerivedProxy(teacher).print()
//直接访问代理类对象的属性
println(DerivedProxy(teacher).message)
}
interface IPerson {
val message: String
fun eat()
fun sleep()
fun print()
}
class Teacher(var name: String) : IPerson {
override val message: String = "Type is Teacher"
override fun eat() {
println("My name is $name ,I'm eating")
}
override fun sleep() {
println("My name is $name ,I'm sleeping")
}
override fun print() {
println(message)
}
}
class DerivedProxy(person: IPerson) : IPerson by person {
override val message: String = "Type is DerivedProxy"
override fun eat() {
println("My name is Proxy ,I'm eating food that belongs to her")
}
}
执行结果如下:1
2
3
4My name is Proxy ,I'm eating food that belongs to her
My name is 邹小雨 ,I'm sleeping
Type is Teacher
Type is DerivedProxy
属性委托
到这里已经和题目相关性不大了,部分事项已经写到注释里啦,请以官方文档为准哦~1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61package DerivedModel
import kotlin.properties.Delegates
import kotlin.reflect.KProperty
/**
* describe: 属性委托
* author: kaithmy
* date: 2018/8/13 17:52
**/
fun main(args: Array<String>) {
val valueTest = ValueTest()
println(valueTest.name)
valueTest.name = "欸嘿嘿"
println(valueTest.lazyBoy)
println(valueTest.lazyBoy)
valueTest.age = 10
valueTest.age = 18
val mapTest = MapTest(mapOf(
"name" to "July",
"age" to 20
))
println(mapTest.name)
println(mapTest.age)
}
//把属性储存在映射中
class MapTest(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
class ValueTest {
var name: String by Delegate()
//标准委托,默认synchronized的
//第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结 果, 后续调用 get() 只是返回记录的结果。
val lazyBoy: String by lazy {
println("lazy inner")
"Hey,boy"
}
//可观察属性
//如果你想能够截获一个赋值并“否决”它,就使用 vetoable() 取代 observable() 。在属性被 赋新值生效之前会调用传递给 vetoable 的处理程序。
var age: Int by Delegates.observable(0) { property, oldValue, newValue ->
println("$oldValue -> $newValue")
}
}
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")
}
}
执行结果如下:1
2
3
4
5
6
7
8
9DerivedModel.ValueTest@3b81a1bc,thank you for delegating name to me!
欸嘿嘿 has been assigned to name in DerivedModel.ValueTest@3b81a1bc
lazy inner
Hey,boy
Hey,boy
0 -> 10
10 -> 18
July
20