代理模式
代理模式是Spring AOP 中大量使用的设计模式,面向切面编程的底层就是使用的代理模式,所以代理模式是比较重要的
一 概述
什么是代理模式
- 概念:为其他对象提供一种代理以控制对这个对象的访问
- 什么意思呢,我们举个例子,租房公司都知道吧,我们想要去租房或者出租房子都会委托给租房公司,因为对于租客来说租房公司有着许多资源,而且随时可以去看房,对于房东来说,他可以避免随时需要去带领租客看房并且商量价格,只需要关注租房本身这件事上,其他的事情都可以交给租房公司。这样的模式就是代理模式。
模式的角色
关于代理模式,我们有四个角色
- 抽象角色:一般会使用接口或者抽象类来解决。
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人。
二 静态代理与动态代理
静态代理
- 下面,我们通过代码实现上面的例子
1.抽象角色:定义了真实角色与代理角色需要实现的方法
//租房
public interface Rent {
public void rent();
}
2.真实角色:房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
3.代理角色:中介
public class Proxy implements Rent{
private Host host;
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
host.rent();
getMoney();
}
public void seeHouse(){
System.out.println("中介带你看房子");
}
public void getMoney(){
System.out.println("交钱");
}
}
4。访客(主函数)
public class MainClass {
public static void main(String[] args) {
Host host = new Host();
Proxy p = new Proxy(host);
p.rent();
}
}
结果:
这样我们就实现了代理模式。通过中介来租房子
但是,我们发现,这样的代理类是写死的,由于每当有一个真实的角色,都需要再来一个对应的代理角色,工作量太大,不易管理。并且代理与真实角色都实现的同一个接口,接口一旦发生改变,代理类也得相应修改
所以我们引出了动态代理
动态代理
在这篇文章中我使用的是JDK实现动态代理,还有一种方式是通过CGLIB实现动态代理,JDK实现的的动态代理只适合于有接口的类,对于没有接口的类只能使用其他方法
在看动态代理之前,你需要一些反射的知识,了解反射包中的Proxy与InvocationHandler两个类
- Proxy 是用来生成动态代理的实例的,就是代理对象。
- InvocationHandler 是由代理实例的调用处理实现的接口的。
我们将上面实现的代理类删除,写一个动态生成代理类的处理类
public class ProxyInvocationHandler implements InvocationHandler{
//被代理的接口
private Object oj;
public void setRent(Object oj){
this.oj = oj;
}
//通过反射得到一个代理对象
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
oj.getClass().getInterfaces(),
this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//选择要执行的接口上的方法
seeHouse();
Object result = method.invoke(oj, args);
getMoney();
return result;
}
public void seeHouse(){
System.out.println("中介带你看房子");
}
public void getMoney(){
System.out.println("交钱");
}
}
再看主函数
public class MainClass {
public static void main(String[] args) {
Host host = new Host();
//代理角色,现在没有,需要动态生成
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host);
//动态生成的代理对象
Rent r = (Rent)pih.getProxy();
r.rent();
}
}
结果
你会发现,我们并没有写代理类,而是通过处理程序动态的生成了一个代理对象,实现了代理模式。我们发现,动态代理处理的是接口,因为他是通过接口来反射生成代理类的。这样我们一个动态代理就可以处理一类业务。大大减少了代码量,而且还降低了与目标接口的耦合程度。
三 代理模式的优点与适用场景
优点
- 可以使真实角色的操作更加纯粹,不用关注一些公共业务
- 公共业务交给了代理角色,实现了业务的分工
- 公共业务发生扩展时,只需要调整代理角色,方便集中管理
- 动态代理一个动态代理类代理的一个接口,一般就是对应一类业务。
适用场景
- 程序可能不希望用户直接访问对象,而是提供一个特殊的对象以控制对当前对象的访问。
四 关于代理模式与装饰模式的想法
- 在学习代理模式的时候,我常常将代理模式与装饰模式混淆,因为对于装饰模式中装饰者和被装饰者都实现同一个 接口。对代理模式来说,代理类和真实处理的类都实现同一个接口,而且两者都是对类的方法进行扩展。
- 想了一会后,我得出了这样的结论:
我们可以代入这样的场景:假如xx明星就是一个具体的类,我们将装饰者看作是这个明星的化妆师,将代理者看作是这个明星的经纪人。假如我们象与这个明星合作,我们需要联系经纪人,在经纪人考察过之后才能再与明星谈,而化妆师只需要将明星花里胡哨的展示在人们面前就可以了。 - 我们专业点:
1.装饰器模式关注于在一个对象上动态的添加方法,强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。增强后你还是你,只不过能力更强了而已
2.代理模式关注于控制对对象的访问,为了实现对象的控制,因为被代理的对象往往难以直接获得或者是其内部不想暴露出来
这就是我所学习的代理模式,如果有什么错误或者你有更好的想法请告诉我。