首页 > 代码库 > Java设计模式—代理模式
Java设计模式—代理模式
代理模式(Proxy Pattern)也叫做委托模式,是一个使用率非常高的模式。
定义如下:
为其他对象提供一种代理以控制对这个对象的访问。
个人理解:
代理模式将原类进行封装,客户端不能直接找到原类,必须通过代理角色。即代理是原类的一个替身,客户端要找原类,统统找代理就可以搞定。明星和经纪人就是一种代理模式。
通用类图如下:
角色定义:
● Subject 抽象主题角色
抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。
● Real Subject 具体主题角色
也叫做被委托角色、被代理角色。它才是冤大头,是业务逻辑的具体执行者。
● Proxy代理主题角色
也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。
通用源代码:
//抽象主题类 public interface Subject { //定义一个方法 public void request(); }
在接口中我们定义了一个方法request来作为方法的代表,RealSubject对它进行实现。
//真实主题类 public class Real Subject implements Subject { //实现方法 public void request() { //业务逻辑处理 } }
Real Subject是一个正常的业务实现类,代理模式的核心就在代理类上。
代理类如下:
public class Proxy implements Subject { //要代理哪个实现类 private Subject subject = null; //默认被代理者 public Proxy(){ this.subject = new Proxy(); } //通过构造函数传递代理者 public Proxy(Object...objects ) { } //实现接口中定义的方法 public void request() { this.before(); this.subject.request(); this.after(); } //预处理 private void before(){ //do something } //善后处理 private void after(){ //do something } }
代理模式的优点:
职责清晰、高扩展性、智能化
案例分析:追星族想要明星签名,必须找其经纪人搞定。
类图如下:
通用源代码如下:
//明星接口 public interface IStar { //明星都会签名 public void sign(); } //明星只有一个行为:签字。我们来看明星的实现,如代码清单3 //明星 public class Singer implements IStar { public void sign() { System.out.println("明星签字:我是XXX大明星"); } } //经纪人与明星应该有相同的行为,比如说签名,虽然经纪人不签名,但是他把你要签名的笔记本、衣服、CD等传递过去让真正的明星签字, //经纪人 public class Agent implements IStar { //定义是谁的经纪人 private IStar star; //构造函数传递明星 public Agent(IStar _star){ this.star = _star; } //经纪人是不会签字的,签字了歌迷也不认 public void sign() { star.sign(); } }
//追星族 public class Idolater { public static void main(String[] args) { //崇拜的明星是谁 IStar star = new Singer(); //找到明星的经纪人 IStar agent = new Agent(star); System.out.println("追星族:我是你的崇拜者,请签名!"); //签字 agent.sign(); } }
很简单,找到明星的代理,然后明星就签字了。运行结果如下所示:
追星族:我是你的崇拜者,请签名!
明星签字:我是XXX大明星
看看我们的程序逻辑,我们是找明星的经纪人签字,真实签字的是明星,经纪人只是把这个请求传递给明星处理而已,这是普通的代理模式的典型应用。
*********************************************************************************************************************************************************************
代理模式的扩展:
普通代理、强制代理、动态代理
普通代理:要求客户端只能访问代理角色,而不能访问真实角色。
在该模式下,调用者只知道代理而不知道真是的角色是谁,屏蔽了真是角色的变更对高层模块的影响,真实的主
题角色想怎么修改都可以。在实际项目中,一般通过约定来禁止new一个真实的角色。
强制代理:客户端必须通过真实角色查找到代理角色,否则你不能访问。
就好比是你和一个明星比较熟,相互认识,有件事情你需要向她确认一下,于是你就直接拨通了明星的电话:
“喂,沙比呀,我要见一下×××导演,你帮下忙了!”
“不行呀衰哥,我这几天很忙呀,你找我的经纪人吧……”
郁闷了吧,你是想直接绕过她的代理,谁知道返回的还是她的代理,这就是强制代理,你可以不用知道代理存在,但是你的所作所为还是需要代理为你提供。
动态代理:
在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态
代理。
首先我们需要学习JDK提供的动态代理接口InvocationHandler,该接口对被代理类的方法进行代理。
JDK如图所示:
其次还有一个类叫Proxy,来看JDK描述,我们主要使用了newProxyInstance( )的静态方法。
动态代理Demo如下:
package com.package1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy { public static void main(String[] args){ //定义一个people作为被代理的实例 IPeople ple=new People(); //定义一个handler InvocationHandler handle=new MyHandle(ple); //获得类加载器 ClassLoader cl=ple.getClass().getClassLoader(); //动态产生一个代理,下边两种方法均可 // IPeople p=(IPeople) Proxy.newProxyInstance(cl, new Class[]{IPeople.class}, handle); IPeople p=(IPeople) Proxy.newProxyInstance(cl, ple.getClass().getInterfaces(), handle); //执行被代理者的方法。 p.func(); } } class MyHandle implements InvocationHandler{ //被代理的实例 Object obj=null; //我要代理谁 public MyHandle(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=method.invoke(this.obj, args); return result; } } interface IPeople{ public void fun(); public void func(); } //实际被代理的类 class People implements IPeople{ @Override public void fun() { System.out.println("这是fun方法"); } @Override public void func() { System.out.println("这是func方法"); } }
其中invoke方法是接口Invocation Handler定义必须实现的,它完成对真实方法的调用。我们来详细讲解一下Invocation Handler
接口,动态代理是根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称“我已经实现该接口下的所有方法
了”,那各位读者想想看,动态代理怎么才能实现被代理接口中的方法呢?默认情况下所有的方法返回值都是空的,是的,代理已经
实现它了,但是没有任何的逻辑含义,那怎么办?好办,通过Invocation Handler接口,所有方法都由该Handler来进行处理,即所
有被代理的方法都由Invocation Handler接管实际的处理任务。
Java设计模式—代理模式