介绍
代理模式类似于生活中的中介,由中介帮忙负责处理相关事情。具体体现为代理类和实现类都实现同一个接口,代理类的实现直接依赖的实现类的逻辑,而自己不处理具体的逻辑。这里用一个工地包工头来描述,老板跟包工头说明要怎么干,包工头清楚后,就安排工地工人实际干活,对于老板来说,不需要知道工人是怎么工作的,只需要知道包工头为他打工。代理模式分为静态代理和动态代理。
静态代理
结构
- 定义一个抽象接口
- 定义一个具体实现类
- 定义一个代理类,关联到实现类,代理类的方法实现依赖实现类
- 场景类中,通过代理类来处理具体的业务逻辑。
类图结构
实现
定义一个建造房子的接口, HouseBuilder
public interface HouseBuilder {
void build();
}
定义一个工人实现类, Worker
public class Worker implements HouseBuilder{
@Override
public void build() {
System.out.println("worker is building house");
}
}
定义一个包工头,WorkerProxy,它实现HouseBuilder,并通过构造函数
关联一个Worker实例
public class WorkerProxy implements HouseBuilder {
private Worker worker;
public WorkerProxy() {
this.worker = new Worker();
}
@Override
public void build() {
System.out.println("WorkerProxy start");
this.worker.build();
System.out.println("WorkerProxy end");
}
}
老板发话了,让包工头去造房子。
public class Boss {
public static void main(String[] args) {
HouseBuilder workerProxy = new WorkerProxy();
workerProxy.build();
}
}
动态代理
介绍
首先来说明下类加载机制,Java类的生命周期分为,java源文件经过编译生成字节码文件(.class),字节码文件经过类加载在jvm中生成一个类对象(Class),这个类对象是所有实例生成依赖的,实例则是具体在程序运行逻辑等,在jvm判断这个实例不可达之后,jvm会对该实例进行回收。前面说的静态代理就是上述过程,然而,如果系统中有很多需要代理的接口,那么每个接口都要有一个实现类和一个代理类,系统则会比较复杂。所以jdk提供一个动态生成代理对象的方法,本质上,jdk创建实例都是由Class对象,所以其实就是jdk根据接口和类加载器反射来生成一个代理类的Class对象,然后代理类对象持有一个处理类来运行具体实现类的方法并增强相关方法。
类图结构
实现
定义一个建造房子的接口, HouseBuilder
public interface HouseBuilder {
void build();
}
定义一个工人实现类, Worker
public class Worker implements HouseBuilder{
@Override
public void build() {
System.out.println("worker is building house");
}
}
定义一个方法增强类WorkerIH,实现InvocationHandler。这个类是对具体的实现类运行过程方法增强的处理类。
public class WorkerIH implements InvocationHandler {
private Object obj;
public WorkerIH(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(obj);
}
}
定义一个boss类
这里通过jdk的Proxy类来动态创建Worker的代理类,然后由代理类来运行具体的方法。
public class Boss {
public static void main(String[] args) {
HouseBuilder worker = new Worker();
InvocationHandler workerIH = new WorkerIH(worker);
HouseBuilder workerProxy = (HouseBuilder) Proxy.newProxyInstance(worker.getClass().getClassLoader(),
worker.getClass().getInterfaces(), workerIH);
workerProxy.build();
}
}
优缺点
上层调用只需要关注代理类,不需要知道具体实现,代理类和实现类关联,符合设计原则。同时,代理类可以在实现类实现原有逻辑的而不改动代码的情况下,对方法进行增强。静态代理适合需要代理类较少且定制性强的场景,而静态代理适合写通用框架等抽象性的场景。