设计模式之代理模式

来源:互联网 发布:加工中心圆怎么编程 编辑:程序博客网 时间:2024/06/06 08:43

在Java的开源框架里,我们经常会遇到代理模式,无论是在Hibernate里面,还是在Struts2里面,以及Spring里,都大量用到了代理模式。而代理模式有分为静态代理和动态代理两种。我们先从简单的开始学起,先看静态代理模式。

静态代理模式

在娱乐圈中,明星们基本上都有经纪人,以为明星要参加一次商业活动,可能要经过许许多多的过程:先面谈,再签合同,再订机票,然后再去参加商业活动,最后收款。这些过程事情都比较琐碎,而明星们都比较忙,因此这些事情可能没有时间亲自去做,也没必要,完全可以委托一个人去谈,这个人就是我们所说的经纪人,明星完全把这些事委托给经纪人代理他去办。这就是所谓 的代理模式。

静态代理模式包含如下部分:

①:抽象角色,代理人和真实角色的抽象;

②:真实角色,也就是被代理的对象,真正做事情的的人,相当于例子中的明星;

③:代理角色,相当于例子中的经纪人。

现在通过具体的代码实现静态代理模式:

在测试代码中,定义了一个Star接口,充当抽象角色;定义了一个RealStar类,实现了Star接口,充当真实角色;定义了一个Agent类,也实现了Star接口,充当代理角色,同时该类中持有一个对真实对象的引用。

package com.tiantang.proxy.dynamicProxy;/** * 代理和被代理对象的共同抽象接口 * @author LiuJinkun * */public interface Star {/** * 双方面谈 */void confer();/** * 签合同 */void signContract();/** * 订票  */void bookTicket();/** * 明星唱歌 */void sing();/** * 收款 */void collectMoney();}
package com.tiantang.proxy.dynamicProxy;/** * 被代理的对象(也是真实角色) * @author LiuJinkun * */public class RealStar implements Star {@Overridepublic void confer() {System.out.println("明星和合作商面谈");}@Overridepublic void signContract() {System.out.println("明星和合作商签合同");}@Overridepublic void bookTicket() {System.out.println("明星订机票");}@Overridepublic void sing() {System.out.println("明星唱歌");}@Overridepublic void collectMoney() {System.out.println("明星收款");}}
package com.tiantang.proxy.staticProxy;/** * 代理对象 * @author LiuJinkun * */public class Agent implements Star{//代理对象持有对真实对象的引用private Star realStar;public Agent(Star realStar){this.realStar=realStar;}@Overridepublic void confer() {realStar.confer();}@Overridepublic void signContract() {realStar.signContract();}@Overridepublic void bookTicket() {realStar.bookTicket();}@Overridepublic void sing() {realStar.sing();}@Overridepublic void collectMoney() {realStar.collectMoney();}}
在Client中测试一下:

package com.tiantang.proxy.staticProxy;public class Client {public static void main(String[] args) {Star realStar=new RealStar();Star proxy=new Agent(realStar);//真实对象(被代理的对象)的所有事情全都交给代理对象去做,//但实际上代理对象还是最终调用真实对象的方法proxy.confer();proxy.signContract();proxy.bookTicket();proxy.sing();proxy.collectMoney();}}

类中调用的代理对象的方法,但实际上最终还是调用的是真实对象的方法。

UML类图如下:


事实上,个人感觉静态代理模式使用起来没有多大的用处,因为代理对象的代码都是静态写好的,当我们需要的代理对象真多时,就需要编写大量的代理类。而真正用处大的是动态代理模式。

动态代理模式:

动态代理是根据程序运行时根据具体需要来创建相应的代理对象,具有可扩展性,而不是实现就创建好代理对象。它需要自定义一个处理器类,并实现InvocationHandler接口,这个处理器负责处理所有真实对象的方法。具体实现代码如下:

package com.tiantang.proxy.dynamicProxy;/** * 代理和被代理对象的共同抽象接口 * @author LiuJinkun * */public interface Star {/** * 双方面谈 */void confer();/** * 签合同 */void signContract();/** * 订票  */void bookTicket();/** * 明星唱歌 */void sing();/** * 收款 */void collectMoney();}
package com.tiantang.proxy.dynamicProxy;/** * 被代理的对象(也是真实角色) * @author LiuJinkun * */public class RealStar implements Star {@Overridepublic void confer() {System.out.println("明星和合作商面谈");}@Overridepublic void signContract() {System.out.println("明星和合作商签合同");}@Overridepublic void bookTicket() {System.out.println("明星订机票");}@Overridepublic void sing() {System.out.println("明星唱歌");}@Overridepublic void collectMoney() {System.out.println("明星收款");}}
package com.tiantang.proxy.dynamicProxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 自定义的处理器类(需要实现InvocationHandler接口) * @author LiuJinkun * */public class MyInvocationHandler implements InvocationHandler{//持有被代理对象的引用(即真实对象)private Object obj;public MyInvocationHandler(Object obj){this.obj=obj;}/** * 动态创建代理对象 * @return */public Object getProxy(){return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result=method.invoke(obj, args);return result;}}
package com.tiantang.proxy.dynamicProxy;/** * 测试动态代理的代码 * @author LiuJinkun * */public class Client {public static void main(String[] args) {Star realStar=new RealStar();MyInvocationHandler handler=new MyInvocationHandler(realStar);Star proxy=(Star) handler.getProxy();proxy.sing();}}

个人感觉其实代理模式的代码基本上都是固定的,相当于公式,当使用时,直接往上套对应的代码即可。没有多大的技术要求。

在Spring的AOP机制中,就大量利用的动态代理和反射,例如我们在开发中增加日志功能时,只需要在处理器类的invoke方法中,method.invoke()方法的前后增加相应的需求即可。当然,在Spring的AOP已经帮我们实现封装好了这些方法,我们只需要拿来使用即可。


1 0
原创粉丝点击