通俗易懂的java设计模式之代理模式

74 阅读3分钟

租房的时候,想要租到合适的房子,往往人们会找中介,原因是中介掌握着大量房源,也可以为人们在租房时提供一定的服务。在这个例子中,中介就充当了代理,而他提供的额外服务和资源就是其在原来租房的功能基础上扩展的功能。

代理分为静态代理和动态代理,二者有何区别呢?

静态代理通俗的说就是已经程序写好的代理类,而动态代理是程序没有写而是通过反射等技术实现的。

一、静态代理

直接上代码:

public class ProxyStatic {
    public static void main(String[] args) {
        //定义租房
        IRentHouse iRentHouse = new RentHouse();
        //定义中介
        IRentHouse intermediaryProxy = new IntermediaryProxy(iRentHouse);
        //中介租房
        intermediaryProxy.rentHouse();
    }
}
interface IRentHouse {
    void rentHouse();
}
class RentHouse implements IRentHouse {
    @Override
    public void rentHouse() {
        System.out.println("实现租房");
    }
}
class IntermediaryProxy implements IRentHouse {
    private IRentHouse iRent;
    public IntermediaryProxy(IRentHouse iRentHouse) {
        iRent=iRentHouse;
    }
    @Override
    public void rentHouse() {
        System.out.println("交中介费");
        iRent.rentHouse();
        System.out.println("中介负责维修管理");
    }
}

可以看到代理类IntermediaryProxy是我们在程序里定义好的。

二、动态代理

动态代理有JDK提供的动态代理和Cglib动态代理

JDK动态代理

还是一样的先上代码

public class ProxyDynamicJDK {
    public static void main(String[] args) {
        IntermediaryProxy proxy = new IntermediaryProxy(new RentHouse());
        //创建代理实例
        IRentHouse student = (IRentHouse) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{IRentHouse.class}, proxy);
        student.rentHouse();
    }
}
interface IRentHouse {
    void rentHouse();
}
class RentHouse implements IRentHouse {
    @Override
    public void rentHouse() {
        System.out.println("实现租房");
    }
}
//代理类
class IntermediaryProxy implements InvocationHandler {
    private Object bean;
    public IntermediaryProxy(Object bean) {
        this.bean=bean;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("交中介费");
        Object invoke = method.invoke(bean, args);
        System.out.println("中介负责维修管理");
        return invoke;
    }
}

运行结果如下:

交中介费
实现租房
中介负责维修管理

特别注意:通过jdk动态代理这种方式被代理的类必须实现接口,没得商量!

Cglib动态代理

Cglib是三方库,需要先引入依赖,另外Cglib基于Asm字节码操控框架,所以还要引入Asm依赖。

我本地引入的为Cglib 3.1版本和Asm 3.3.1版本

引入依赖后,就可以实现啦,上代码:

public class ProxyDynamicCglib {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RentHouse.class);
        enhancer.setCallback(new MyApiInterceptor());
        RentHouse rentHouse = (RentHouse) enhancer.create();
        rentHouse.rentHouse();
    }
}
class RentHouse {
    public void rentHouse() {
        System.out.println("实现租房");
    }
}
class MyApiInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("交中介费");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("中介负责维修管理");
        return result;
    }
}

细心的你发现了,通过Cglib动态代理这种方式被代理的类不需要实现接口

代理模式讲完了,不知道你发现了没有,它和装饰模式有些相似,那它俩没有区别吗?其实要知道的是装饰模式只对原对象做了增强,原对象仍然可以被外界所调用,而通过代理的方式被代理类不能被外界所调用

总结

  1. 代理模式可以在目标方法调用前或者后增加新功能。
  2. 动态代理中JDK动态代理被代理类需要实现接口而Cglib不需要。
  3. 被代理类不能被外界调用,只能通过代理类间接调用。