代理模式

定义

为其他对象提供一种代理以控制对这个对象的访问

应用场景

  • 远程代理:也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实(Binder机制)。
  • 保护代理:用来控制真实对象访问时的权限。
  • 智能引用代理:当调用目标对象时,代理可以处理其他的一些操作。

UML类图

代理模式

静态代理

在编写代码期间为每个被代理的对象编写对应的代理类,达到对应的代理功能

代码示例

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
public class StaticProxy {
public static void main(String... args) {

RealStudent student = new RealStudent();
IStudent s = new StudentProxy(student);
s.doHomework();
}

interface IStudent {
void doHomework();
}

/**
* 被代理类,真正的执行者
*/
static class RealStudent implements IStudent {

@Override
public void doHomework() {
System.out.println("doing homework...");
}
}

/**
* 代理类
*/
static class StudentProxy implements IStudent {

private IStudent realStudent;

public StudentProxy(IStudent realStudent) {
this.realStudent = realStudent;
}

@Override
public void doHomework() {
if (realStudent != null) {
realStudent.doHomework();
} else {
// do nothing
}
}
}

}

实例:
WeakHandler

优点:在编译期加入,提前就指定好了谁调用谁,效率高。
缺点:如果要想为多个类进行代理,则需要建立多个代理类,维护难度加大。

动态代理

由于每一个静态代理类只能为一个接口服务,工程中有可能产生很多代理类,所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理

代码示例

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
public class DynamicProxy {
public static void main(String... args) {
RealStudent student = new RealStudent();
Class<?>[] inters = new Class[]{IStudent.class};
IStudent s = (IStudent) Proxy.newProxyInstance(student.getClass().getClassLoader(), inters, new StudentProxy(student));
s.doHomework();
}

interface IStudent {
void doHomework();
}

/**
* 被代理类,真正的执行者
*/
static class RealStudent implements IStudent {

@Override
public void doHomework() {
System.out.println("doing homework...");
}
}

/**
* 代理类
*/
static class StudentProxy implements InvocationHandler {

private IStudent realStudent;

public StudentProxy(IStudent realStudent) {
this.realStudent = realStudent;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (realStudent != null) {
return method.invoke(realStudent, args);
} else {
return null;
}
}
}

}

动态代理原理:
运行时按照Class文件标准格式结合JNI的defineClass0()方法生成Proxy匿名代理类,该类实现了需要代理的接口,并返回这个代理类的实例对象给调用者。

1
2
// 保存Proxy生成的中间类到根目录
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

实例:
Retrofit

优点:高扩展性
缺点:

  1. 实现比静态代理复杂,不好理解
  2. 要求代理对象必须实现了某个接口