代理模式
简单来说就是代理对象起到中介的作用
流程也就是:使用者 - 代理 - 服务者
用图表示则为:
好处
可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
因为别人写的代码是可以正常运行的,如果随便修改源代码出现bug了就难顶了~
因此如果需要修改,可以通过代理的方式来扩展该方法
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.
例子
我们定义一个接口
public interface Store {
void sale();
}
然后定义一个实现类
public class StoreImpl implements Store{
@Override
public void sale() {
System.out.println("卖东西");
}
}
然后定义代理
public class StoreProxy implements Store {
private Store targetObj;
public StoreProxy(Store targetObj) {
this.targetObj = targetObj;
}
@Override
public void sale() {
System.out.println("前驱代码");
targetObj.sale();
System.out.println("后继代码");
}
}
测试
public class Test {
public static void main(String[] args) {
Store store = new StoreImpl();
StoreProxy proxy = new StoreProxy(store);
proxy.sale();
}
}
执行结果
前驱代码
卖东西
后继代码
综上所述
一、好处:
可以做到在不修改目标对象的功能前提下,对目标功能扩展.
二、缺点:
①因为代理类需要与实现类实现一样的接口,所以会有很多代理类
②一旦接口增加方法,目标对象与代理对象都需要修改
为了解决这些缺点 我们引入动态代理
动态代理
动态代理有以下特点:
①.不需要实现接口
②.代理对象的生成是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
③因此动态代理也叫做:JDK代理,接口代理
使用的API
java.lang.reflect.Proxy类的
/**
*
* @param loader 指定当前目标对象使用类加载器
* @param interfaces :目标对象实现的接口的类型
* @param h 事件处理,执行目标对象的方法时,会触发事件处理器的方法,
* 会把当前执行目标对象的方法作为参数传入。简单来说就是=>如何代理
* @return
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h){
}
例子
接口和实现类跟静态代理是一样的,就不重复写了.
首先是一个创建代理对象的工厂
package ProxyDemo.DynamicProxyDemo;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
private StoreImpl targetObj;
public ProxyFactory(StoreImpl targetObj) {
this.targetObj = targetObj;
}
public Object createProxyInstance(){
return Proxy.newProxyInstance(targetObj.getClass().getClassLoader()
, targetObj.getClass().getInterfaces(),
(Object proxy, Method method, Object[] args) -> {
System.out.println("前驱代码");
//这里args写不写都行 因为是args里啥都没有
Object obj = method.invoke(targetObj,args);
System.out.println("后继代码");
return obj;
});
}
}
然后是测试
public class Test {
public static void main(String[] args) {
StoreImpl obj = new StoreImpl();
Store proxy = (Store) new ProxyFactory(obj).createProxyInstance();
proxy.sale();
}
}
执行结果
前驱代码
卖东西
后继代码
总结
动态代理不需要实现接口,但是目标(实现类)对象通常要实现接口,否则不能用动态代理。
目标对象的方法就是让代理对象调用invoke来执行的
当然我们也可以不写实现类,那么在说明如何代理的时候
也就是传递InvocationHandler h
这个参数的时候 说明如何代理即可。换句话说就是把invoke的内容移动到这了而已。
至于不写实现类的例子…咕咕咕,有缘再更