一、什么是代理
现在有三个人:农民、秘书和领导。
农民要去找领导盖章,但是领导很忙,然后就授权秘书可以代替领导进行盖章操作。
这时候,秘书就代理了领导进行盖章。
这个秘书呢,为了谋取私利,找他盖章的人都要缴纳20元的手续费!
秘书在代理领导盖章工作以外,有增加了一项业务(收手续费),这就是代理的“好处”。
代理(秘书)提供了农民对目标对象(领导)的间接访问方式,农民通过代理(秘书)访问目标对象(领导)。
这样就便于在目标实现(领导盖章)的基础上增加额外的功能操作(收手续费),这个额外操作(收手续费)可以在
实现目标对象(盖章)之前操作,也可以在(盖章)其之后操作。以满足自身的业务需要。
代理模式便于扩展目标对象功能(盖章+收手续费)。
二、什么是静态代理呢?
领导不只一个,还有签字的领导A、调研的领导B、剪彩的领导C。。。
但是秘书只代理了盖章领导,秘书就只有代理盖章的功能。如果农民找秘书签字,
秘书是无法签的,农民还是要找领导A去签字,这就是“静态代理”!秘书的代理功能单一。
具体实现:代理类(秘书)通过实现与目标对象(签字领导)相同的接口(盖章),
并在类中维护一个代理对象。通过构造器塞入目标对象,赋值给代理对象,进而执行代理对象实现的接口方法,
并实现前拦截(收费),后拦截等所需的业务功能。
具体实现如下:
/**
* 目标对象实现的接口(盖章)
*/
public interface BussinessInterface {
void execute();
}
/**
* 目标对象实现类(签字领导)
*/
public class Bussiness implements BussinessInterface{
@Override
public void execute() {
System.out.println("盖章。。。");
}
}
/**
* 代理类(秘书),通过实现与目标对象(领导)相同的接口(盖章)
* 并维护一个代理对象,通过构造器传入实际目标对象并赋值
* 执行代理对象实现的接口方法,实现对目标对象实现的干预
*
*/
public class BussinessProxy implements BussinessInterface{
private BussinessInterface bussinessImpl;
public BussinessProxy(BussinessInterface bussinessImpl) {
this.bussinessImpl = bussinessImpl;
}
@Override
public void execute() {
System.out.println("收手续费");
bussinessImpl.execute();
System.out.println("其他工作");
}
}
通过以上代码看到,因为代理对象,需要实现与目标对象一样的接口,如果有多个需要代理的对象,导致代理类也会很多,不易维护,如果增加接口中的方法,代理对象也需要维护。
三、什么是动态代理?
但是领导A、B、C太忙了,于是有了秘书处,秘书处专门“生产秘书”,盖章的秘书、签字的秘书、调研的秘书等都有。
无论是什么领导,秘书处都能“生产”出代理他们的秘书。农民只需找秘书处就行了。
这样就灵活了,无论是什么领导,秘书处都能有对应的秘书代理领导干活。这个秘书处就是“动态代理”。
动态代理是指(秘书处)动态的在内存中构建代理对象(秘书)(需要我们制定要代理的目标对象(领导们)实现的接口类型),即利用JDK的API生成指定接口的对象,也称之为JDK代理或者接口代理。
动态代理实现如下:
/**
* 动态代理对象(秘书),无需实现任何接口
* 通过传入任何类型的目标对象(任何领导)并指定接口
* 调用JDK接口动态创建代理对象
*/
public class ProxyFactory {
private Object targetObject;
public ProxyFactory(Object targetObject) {
this.targetObject = targetObject;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(), //和目标对象的类加载器保持一致
targetObject.getClass().getInterfaces(), //目标对象实现的接口,因为需要根据接口动态生成对象
new InvocationHandler() { //InvocationHandler:事件处理器,即对目标对象方法的执行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("收费");
Object result = method.invoke(targetObject, args);
System.out.println("干其他活");
return result;
}
});
}
}
那农民怎么找秘书进行具体的工作呢?
代码如下:
public class Client {
@Test
public void dynamicProxy(){
//农民想找签字的秘书
Bussiness bussiness = new Bussiness();
//告诉秘书处,我想找签字的秘书。秘书处生产了能够签字的秘书
Object obj = new ProxyFactory(bussiness).ProxyInstance();
BussinessInterface bussinessImpl = (BussinessInterface)obj;
//秘书签字
bussinessImpl .excute();
}
}
动态代理的优势:代理对象无需实现接口,免去了编写很多代理类的烦恼,同时接口增加方法也无需再维护代理对象,只需在事件处理器中添加对方法的判断即可。