在生活中有很多代理模式,像一些房屋中介,快递员,外卖小哥都是在中间帮我们做一些中间服务,这是一类代理的体现。
代理模式是指为其它对象提供一种代理,以便控制这个对象的访问。代理的对象在客户端和目标对象之间起到中介的作用,代理模式属于结构型。
目的:
- 保护目标对象
- 增强目标对象
下面以租房为例
自己想租一个房子住,于是找到了中介,在中介的帮助下成功找到房子。
House为顶级接口,MyRenting(被代理对象)为个人租房,实现House接口说明租房要求,Realtor是代理对象(房屋中介)为别人寻找合适要求房子。
静态代理
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
- 顶级接口
/**
* 房子顶级接口
*/
public interface House {
//租房
void renting();
}
- 被代理类
/**
* @Class MyRenting
* @Description: 我想找房子租
* @Author Eternal
* @Version
* @date 2019/12/4 20:28
*/
public class MyRenting implements House{
@Override
public void renting() {
System.out.println("想找一个不漏雨的房子");
}
}
- 代理类
/**
* @Class Realtor
* @Description: 中介
* @Author Eternal
* @Version
* @date 2019/12/4 20:29
*/
public class RealtorProxy implements House {
private House house;
public RealtorProxy(House house) {
this.house=house;
}
@Override
public void renting() {
System.out.println("帮别人找房,询问要求:");
house.renting();
System.out.println("成功找到房子!!!");
}
}
- 运行
public class Run {
public static void main(String[] args) {
RealtorProxy realtor = new RealtorProxy(new MyRenting());
realtor.renting();
}
}
- 结果
帮别人找房,询问要求:
想找一个不漏雨的房子
成功找到房子!!!
代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
动态代理
在程序运行时,运用反射机制动态创建而成。解决了静态代理的无法扩展和非次顶级接口无法使用问题
- 动态代理
public class DynamicProxy implements InvocationHandler {
private Object obj;
public Object getInstance(Object obj){
this.obj=obj;
Class<?> clazz = obj.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this::invoke);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object invoke = method.invoke(obj, args);
System.out.println(invoke);
after();
return invoke;
}
private void before(){
System.out.println("before");
}
private void after(){
System.out.println("after");
}
}
- 运行
public class Run {
public static void main(String[] args) {
DynamicProxy proxy = new DynamicProxy();
House house =(House) proxy.getInstance(new MyRenting());
house.renting();
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
System.out.println();
List<String> instance = (List<String>)proxy.getInstance(list);
instance.get(0);
System.out.println();
instance.get(1);
System.out.println();
instance.get(2);
}
}
- 结果
before
想找一个不漏雨的房子
null
after
before
1
after
before
2
after
before
3
after
通过这个结果可以很明显看出,动态代理就可以不用实现固定的接口,像日志记录等就很合适用动态代理去弄。无侵入式记录,不影响原先代码逻辑。
- 区别
- 静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,代理类需要同步增加违反开闭原则
- 动态代理采用在运行时动态生成代码的方式,取消对代理类的扩展限制,遵循开闭原则
- 动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码
- 优点
- 代理对象和被代理目标对象进行分离
- 降低系统耦合度
- 保护目标对象
- 增强目标对象功能
- 缺点
- 造成系统设计中类的数量增加
- 请求速度减慢
- 增加系统复杂度