代理模式是Java中使用十分广泛的一种设计模式,代理模式就是客户端(调用者、访问者)不直接的调用(访问)实际对象,而是通过访问代理对象间接的去访问实际对象。
理解代理模式前先了解几个概念:
- 抽象角色:定义真实角色和代理角色都要遵守的规则
- 真实角色:实现抽象角色,提供真实业务处理逻辑
- 代理角色:需要实现抽象角色,通过真实角色的业务逻辑,来实现客户端的访问。。。
代理模式的分类:
- 静态代理
- 动态代理
以前在网上看到过用老板和助理来举例代理模式的:
public class Boss{}
public class Assistant{}
一、静态代理模式
设置这样一个场景:有一个人A要见这个老板,和老板谈谈人生、聊聊理想;
在这个场景中 A就是客户端(调用者、访问者);老板就是真实角色(A真正要谈人生聊理想的对象);助理就是代理角色(老板不是想见就见的,需要通过助理预约)
使用静态代理,我们先要提取一个对外接口,真实对象和代理对象都实现
public interface ProxyInterface{ void talk(); //谈人生,聊理想}
public class Boss implements ProxyInterface {
@Override
public void talk(){
//老板实现谈人生聊理想的逻辑
}
}
public class Assistant implements ProxyInterface {
private ProxyInterface proxyInterface; //助理需要持有老板对象
public Assistant(ProxyInterface proxyInterface){
this.proxyInterface = proxyInterfac;
}
@Override
public void talk(){
proxInterface.talk(); //助理通过老板对象也可以谈理想
}
}
当访问者要和老板谈理想时,就可以这样操作
//不直接访问老板,而是通过助理
ProxyInterface proxy = new Asstanct(new Boss());
proxy.talk();//这里的代理(助理)就代表了老板,不要拘泥于显示中一定要和老板面对面
这样举例很多人会疑惑,还不如直接通过老板对象简单,在扩展一下,老板是很忙的,要和老板聊天前,总要看看老板的日程安排吧,然后找个空闲时间安排聊天,安排好后还得找个地方才能聊天吧,聊完后还需要有一些后续的工作等,这一整套流程除了老板具体的聊天内容,其余的都是套路性质的,不需要老板亲自处理,这个时候代理对象就可以代劳了。
public class Assistant implements ProxyInterface {
...
@Override
public void talk(){
//1.看看老板什么时候有时间,安排空余时间
//2.安排地点
proxyInterface.talk();
//3.后续工作
}
}
想这样实现,老板(真实角色)的功能是不是更纯粹了呢,很多时候不需要修改源代码,只需要代理对象就能扩展业务逻辑;
其实可以在扩展一下,公司有多个老板,但助理就一个,助理需要代理更多的老板了,该怎么处理
二、动态代理
当需要代理的对象多了,代理对象需要持有的真实对象就会很多,而且没有需要要代理的对象都需要实现我们定义的接口,一旦接口有该多,实现对象都需要该多。会很冗余且不利于解耦,此时就可以使用动态代理:
动态代理:静态代理中,代理类是我们手写代码实现的,而在动态代理中,是借助程序自动实现。
还是用上面的例子举例:定义一个接口,定义真实对象类,动态代理类(使用JDK方式实现,依赖反射)
public interface ProxyInterface{ void talk(); }//接口
//真实角色类
public class Boss implements ProxyInterface {
@Override
public void talk();
}
//动态代理类
public class ProxyHandler implements InvocationHandler {
private ProxyInterface pxyInterface;
public ProxyDyna(ProxyInterface pxyInterface){
this.pxyInterface = pxyInterface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1 查看老板日程安排...
// 2 ....
Object res = method.invoke(pryInterface, args);
// 3 ...
return res;
}
}
此时通过代理访问需要:
ProxyInterface pxyInterface = new Boss();
ProxyHandler handler = new ProxyHanlder(pxyInterface);
//创建动态代理对象
ProxyInterface proxy = (ProxyInterface).newProxyInstance(x.getClassLoader(),new Class[]{ProxyInterface.class},handler);
//创建的proxy 对象, 是实现了代理接口的,可以调用接口中的所有方法
proxy.talk();
//当创建的动态代理对象调用接口定义的任意方法时,会直接进入动态代理类ProxyHandler 中的 invoke(...)方法中
// 使用method.invoke(pryInterface,args); 就是调用真实角色的 原方法
//我们可以在调用前后添加业务处理,例如 重写方法中 1. 查查日常安排 等