设计模式篇—代理模式详解代理模式的定义
现实生活中经常听到一个词“代理”,比如某某酒品牌什么什么省总代理;还有像现在的明星都有自己的经纪人,有事需要找他们的时候就要先找他们的经纪人,经纪人也相当于是一个代理;再比如打官司都需要找一个律师,有什么问题直接由律师去沟通解决,那律师就是自己的一个代理。
生活中的代理随处可见,Java中也存在一种设计模式,就叫代理模式,并且使用非常普遍,很多著名框架和开源项目的源码中都有大量使用代理模式,比如比较流行的Spring、MyBatis等,都有用到代理模式。特别是MyBatis,代理模式随处可见。那到底什么是代理模式呢?
代理模式也叫做委托模式,是指为其他对象提供一种代理以控制对这个对象的访问。代理模式可以分为静态代理和动态代理,动态代理又分为JDK提供的动态代理和CGLIB动态代理,具体实现及原理下面会进行详细介绍。代理模式的三个角色代理模式中存在三个角色:
1.抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
2.代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
3.真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。这三个角色之间的关系可以用一张简单的类图来表示:
静态代理
静态代理很简单,代理角色和真实角色继承同一个父类或实现相同的接口,使用时只需要把真实角色传递给代理角色,代理角色调用真实角色的方法就可以了。我们举一个游戏代练的例子,我们找游戏代练一般会找专业的代练公司,代练公司有很多代练人员,在这里,我就相当于客户端,代练公司相当于代理角色,代练人员就是真实执行任务的真实角色。我们设计出了如下类图:
顶层接口IGamePlayer中定义了待实现的业务方法:
代理类源代码:
真实角色GamePlayer类的源代码:
客户端进行调用的源代码:
以上就是使用代理模式模拟的一个游戏代理的场景。静态代理的优缺点优点:
1.真实角色类(业务类)只需要关注业务逻辑本身,这是代理模式的共有优点;
2.代理类可以在调用业务类的处理方法之前和之后做一些增强性的操作,比如记录日志、管理事务等,这也是代理模式共有的优点。缺点:
1.代理类和业务类实现了相同的接口,并且实现了相同的方法,代码冗余。如果接口增加一个方法,所有的代理类和所有的实现类都需要增加这个方法的实现,不易维护;2.代理对象只能代理同一种类型的对象,如果要对多种类型的对象进行代理,就要写多个代理类,这就会大大增加类文件的数量,不适合在大规模程序中使用。针对静态代理的这些缺点,JDK提供了动态代理。JDK动态代理
动态代理的代理类是在程序运行的时候由Java反射机制动态生成的。我们在上面静态代理的例子中,代理类GamePlayerProxy是自己定义好的,在程序运行之前就已经编译完成。我们先来看下如何实现JDK的动态代理。
Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,JDK动态代理的实现主要依靠这两个对象实现。
1.创建一个类,实现InvocationHandler接口,并重写它的invoke方法:
这个类中持有一个被代理对象的实例target,还有一个invoke方法,这个方法中通过反射机制调用被代理对象target的method方法,所有执行代理对象的方法都会被替换成执行invoke方法。
2.创建被代理对象的接口,此处还以上面的游戏代练为例子:
3.创建实际要被代理的对象:
4.创建代理对象,并执行要代理的方法:
通过以上4步,我们就通过动态代理实现了一个代练游戏的场景。JDK动态代理的原理
动态代理使用起来很方便,那它底层是如何实现的呢?在上面的例子中,我们通过调用Proxy类的newProxyInstance方法创建了一个代理对象,我们首先来看下这个方法的源码:
设计模式篇—代理模式详解
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)