结构型设计模式之代理模式

来源:互联网 发布:淘宝查号网址 编辑:程序博客网 时间:2024/05/18 16:39

代理模式的介绍

代理模式(Proxy Pattern)也称为委托模式,属于结构型设计模式。其实不少设计模式中都有代理模式的影子,那么何为代理呢?
其实代理在我们日常生活中并不少见,对于程序员来说莫过于代理上网了,连上代理服务器地址,就可以轻松畅游全世界的网络,还有每天吃饭时赶进度是常事,叫朋友帮忙买饭也是一种代理。总而言之,也许你并不留意,但是代理的确是无处不在的,现实生活中如此,我们的Code世界里也是如此!

代理模式的定义

为其他对象提供一种代理以控制对这个对象的访问

代理模式的使用场景

当无法或不想直接访问某个对象存在困难时就可以通过一个代理对象来间接访问,为了保证客户端使用的透明度,委托对象与代理对象必须实现相同的接口

代理模式的简单实现

举一个生活中的例子,小李以前在公司上班时,就遇到被老板拖欠工资甚至克扣工资的情况,这种情况下,小李还是通过法律途径来解决问题,一旦小李选择了走法律途径解决该纠纷,那么不可避免地就需要请一个律师来作为自己的诉讼代理人,我们将诉讼流程抽象在一个接口类中。

//诉讼接口类public interface ILawsuit{//提交申请void submit();//进行举证void burden();//开始辩护void defend();//诉讼完成void finish();}

4个方法非常简单,都是诉讼的一般流程。

//具体诉讼人public class XiaoLi implements ILawsuit{@Overridepublic void submit(){//老板欠小李工资 小李只好申请仲裁System.out.println("老板拖欠工资!特此申请仲裁");}@Overridepublic void burden(){//小李证据充足,不怕告不赢System.out.println("这是合同书和过去一年的银行工资流水!");}@Overridepublic void defend(){//铁证如山,辩护也没什么好说的System.out.println("证据确凿!不需要再说什么了");}@Overridepublic void finish(){//结果也是肯定的,必赢System.out.println("诉讼成功!判决老板即日起七天内结算工资");  }}  

如上所诉,该类实现ILawsuit并对其中4个方法做出具体的实现逻辑,逻辑很简单,都只是输出一段话而已,当然,小李自己是不会去打官司的,于是小李请个律师代替自己进行诉讼。

//代理律师public class Lawyer implements ILawsuit {private ILawsuit mLawsuit;//持有一个具体被代理者的引用public Lawyer(ILawsuit lawsuit){mLawsuit=lawsuit;}@Overridepublic void submit(){mLawsuit.submit;}@Overridepublic void burden(){mLawsuit.burden;}@Overridepublic void defend(){mLawsuit.defend;}@Overridepublic void finish(){mLawsuit.finish;  }}

律师类表示代理者律师,在该类里面会持有一个被代理者(这里也就是上面的Aige类)的引用,律师所执行的方法实质上就是简单调用被代理者中的方法,下面来看看客户类中具体的调用执行关系。

//客户类public class Client{public static void main(String[] args){//构造一个小李...ILawsuit xiaoli = new XiaoLi();//构造一个代理律师并将小李作为构造参数传递进去ILawsuit lawyer = new Lawyer(xiaoli);//律师提交申请 lawyer.submit();//律师进行举证lawyer.burden();//律师开始辩护lawyer.defend();//律师诉讼完成lawyer.finish();   }}   

运行结果很简单这里不再给出,大家可以看到,其实代理模式也很简单,其主要还是一种委托机制,真实对象将方法的执行委托给代理对象,而且委托的干净利索毫不做作,这也是为什么代理模式也称为委托模式的原因,相信大家不难理解。除此之外还可以继续发散思维,其实我们的代理完全可以代理多个被代理类,就想上面的例子一样,一个律师可以代理多个人打官司,这是没有任何问题的,而具体到底是代理哪个人,这就要看代理类中所持有的实际对象类型,上述的例子中实际对象类型是XiaoLi,也就是代理的XiaoLi。

那么在此提出一个问题代理其他人可以吗?
答案是可以的,比如小明,我们只需要在定义XiaoMin类实现ILawsuit即可,再在客户端修改高层模块的调用逻辑,完全没有问题。


代理模式可以大致分为两部分,一是静态代理,二是动态代理。静态代理如上述示例那样,代理者的代码由程序员自己或通过一些自动化工具生成固定的代码再对其进行编译,也就是说在我们代码运行前代理类的class编译文件就已经存在了;而动态代理则与静态代理相反,通过反射机制动态地生成代理者的对象,也就是说我们在code阶段压根就不需要知道代理是谁,代理谁我们将会在执行阶段决定。而Java也给我们提供了一个便捷的动态代理接口InvocationHandler,实现该接口需要重写其调用方法invoke.

//动态代理类public class DynamicProxy implements InvocationHandler{private Object obj; //被代理的类引用public DynamicProxy(Object obj){this.obj=obj;}@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws Throwable{//调用被代理类对象的方法Object result=method.invoke(obj,args);return result;  }}  

从上代码所述,我们声明一个Object的引用,该引用将指向被代理类,而我们调用被代理类的具体方法则在invoke方法中执行,是不是很简洁? 也就是说我们原来由代理类所做的工作现在由InvocationHandler来处理,不再需要关心到底代理谁。下面我们修改客户类的逻辑。

//修改好的客户类public class Client{public static void main(String[] args){//构造一个小李ILawsuit xiaoli=new XiaoLi();//构造一个动态代理DynamicProxy proxy = new DynamicProxy(xiaoli);//获取被代理类小李的ClassLoaderclassLoader loader=xiaoli.getClass().getClassLoader();//动态构造一个代理者律师ILawsuit lawyer=(ILawsuit) Proxy.newProxyInstance(loader,new Class[] {ILawsuit.class},proxy);//律师提交申请 lawyer.submit();//律师进行举证lawyer.burden();//律师开始辩护lawyer.defend();//律师诉讼完成lawyer.finish();}}

运行结果与之前一致,不再给出。由此可见动态代理可以通过一个代理类来代理N多个被代理类,其实质是对代理者与被代理者进行解耦,使两者直接没有直接的耦合关系。相对于静态代理则只能为给定接口下的实现类做代理,如果接口不同就需要重新定义不同地代理类,较为复杂,但是静态代理更符合面向对象原则。

原创粉丝点击