一、介绍
有些场景客户端和目标类之间无法直接建立联系,这时候需要一个中介来建立沟通的桥梁,代理模式可以用来处理这类问题。代理模式是系统通过代理类实现目标同样的功能,并且在实现功能之前和实现功能之后都能对业务进行拓展,实现在不修改目标类的基础上对系统进行拓展,遵循开闭原则。代理模式分为静态代理和动态代理两种方式。
二、静态代理
1、UML类图
静态代理静态代理是指,代理类和目标类实现同一个接口,实现同样的方法,代理类持有目标类的对象引用,并在方法实现中调用目标类方法,在此基础上根据需要进行拓展。
2、代码实例
public interface IRentHouse {
void rentHouse();
}
public class RentHouse implements IRentHouse{
@Override
public void rentHouse() {
System.out.println("实现租房");
}
}
public class IntermediaryProxy implements IRentHouse{
private final IRentHouse mRentHouse;
public IntermediaryProxy(IRentHouse rentHouse) {
mRentHouse = rentHouse;
}
@Override
public void rentHouse() {
System.out.println("寻找中介代理");
mRentHouse.rentHouse();
System.out.println("中介后期房屋维护");
}
}
在代理类中的rentHouse方法实现中调用了目标类的rentHouse方法,在调用目标类的方法之前和之后都可以根据业务需要对系统进行拓展。
3、小结
静态代理要求代理类和目标类必须实现同一个接口,当接口中定义的方法发生变化时,代理类和目标类都要做出相应的改变,代理模式存在诸多限制,平时开发中很少用到。
三、动态代理
动态代理不再要求代理类和目标类要实现同一个接口,动态代理通过Java反射机制来实现代理类一个方法对目标类多个方法的代理。动态代理又分为JDK动态代理(接口代理)和CGlib动态代理。
1、JDK动态代理
JDK动态代理主要是通过实现InvocationHandler接口,实现接口中定义的invoke方法来完成代理。代码实例如下:
public class JDKDynamicProxy implements InvocationHandler {
private final Object bean;
public JDKDynamicProxy(Object bean) {
this.bean = bean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
switch (name){
case "sound":
System.out.println("叫声~");
break;
case "eat":
System.out.println("吃饭~");
break;
}
return method.invoke(bean,args);
}
}
其中构造方法传入的Object对象就是要代理的目标类。
2、CGlib动态代理
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。项目中使用CGLIB动态代理需要引进cglib相应的依赖,主要是通过MethodInterceptor、Enhancer来实现。代码实例如下:
public class CglibProxy implements MethodInterceptor {
private final Object bean;
public CglibProxy(Object bean) {
this.bean = bean;
}
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String name = method.getName();
switch (name){
case "sound":
System.out.println("叫声,此处拓展。。。");
break;
case "eat":
System.out.println("吃饭,此处拓展。。。");
break;
}
return method.invoke(bean,objects);
}
}
四、总结
代理模式更注重与客户端和目标类之间的媒介作用,解决当客户端不便直接调用目标类时存在的问题;装饰器模式更注重对原生类功能的增加。装饰器模式中装饰类在继承目标类的同时还需要聚合目标类的引用,代理模式更多是通过反射机制来实现。
网友评论