四、代理模式
1 代理模式?
为其他对象提供一种代理,用以完成对这个对象的控制访问。
记忆方法:
/**
* 记忆方法:抽象出一个接口,代理类和真实的操作对象都实现接口
* 代理类中通过构造方法注入真实要操作的对象
* 代理中在调用真实对象的方法之前,完成验证。
*/
2 代理模式的应用场景?
应用一:远程访问!本地通过代理完成对远端的访问。那么为什么本地不直接去访问远端,非要经过一个代理呢?一种情况是你需要调用的对象在另外一台机器上,你需要跨越网络才能访问,如果让你直接coding去调用,你需要处理网络连接、处理打包、解包等等非常复杂的步骤,所以为了简化客户端的处理,我们使用代理模式,在客户端建立一个远程对象的代理,客户端就象调用本地对象一样调用该代理,再由代理去跟实际对象联系,对于客户端来说可能根本没有感觉到调用的东西在网络另外一端,这实际上就是Web Service的工作原理。
应用二:虚拟代理,就是耗时操作交给代理完成。达到性能的优化。了比如说你打开一个很大的HTML网页时,里面很多的文字和图片,如果一次性把所有的图片和文字加载完毕以后才显示,可能需要等很长时间,这样的体验很差。如果先把文字一次性呈现出来,然后图片的加载交给代理慢慢的加载出来,这样的体验较好。
应用三:安全代理,就是在访问真实的目标对象前,在代理中实现拦截(安全验证等)。
应用四:增加额外的功能。除了当前类能够提供的功能外,我们还需要补充一些其他功能。最容易想到的情况就是权限过滤,我有一个类做某项业务,但是由于安全原因只有某些用户才可以调用这个类,此时我们就可以做一个该类的代理类,要求所有请求必须通过该代理类,由该代理类做权限判断,如果安全则调用实际类的业务开始处理。可能有人说为什么我要多加个代理类?我只需要在原来类的方法里面加上权限过滤不就完了吗?在程序设计中有一个类的单一性原则问题,这个原则很简单,就是每个类的功能尽可能单一。为什么要单一,因为只有功能单一这个类被改动的可能性才会最小,就拿刚才的例子来说,如果你将权限判断放在当前类里面,当前这个类就既要负责自己本身业务逻辑、又要负责权限判断,那么就有两个导致该类变化的原因,现在如果权限规则一旦变化,这个类就必需得改,显然这不是一个好的设计。
3 代理模式的优点?
如上应用四所说,可以实现单一职责原则。业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
4 静态代理的实现demo:(包含安全验证)
静态代理的缺点:
1)如下demo中,只代理了真实对象的一个方法,request,如果要代理的方法很多,那就需要很多的代理,这样开销大。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
package com.biao.proxy.second; public class ProxyDemo { public static void main(String[] args) { Subject target=new RealSubject(); Subject proxy=new StaticProxy(target); // proxy.request("abc"); //测试1,被拦截,不通过 proxy.request("hello"); //测试2,验证通过。 } } //抽象角色 interface Subject { public void request(String param); } /*目标角色*/ class RealSubject implements Subject{ @Override public void request(String param) { System.out.println("真实请求成功"); } } /*静态代理,通过构造方法注入一个真实的需要被代理的对象*/ class StaticProxy implements Subject{ Subject realSubject; public StaticProxy(Subject realSubject) { this.realSubject=realSubject; } public void before(String param){ if(param.equals("abc"))//验证参数 throw new IllegalArgumentException(); } @Override public void request(String param) { before(param);//请求之前先进行验证,用代理实现验证。 realSubject.request(param); } }
5 动态代理解决静态代理的缺点?
动态代理类的对象是在程序运行期间由JVM根据反射等机制动态的生成,也就是不用一次创建那么多的代理对象,当需要代理的时候(程序运行),才去创建对象,这样开销小。
动态代理的实现demo如下;
package com.biao.proxy.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxyDemo { public static void main(String[] args) { Subject target=new RealSubject(); //第一个参数是目标对象的类加载器,第二个参数是目标类实现的接口,第三个参数是处理器InvocationHandler Subject proxy=(Subject)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new ProxyHandler(target)); // proxy.request("abc"); //测试1 proxy.request("hello"); //测试2 } } /*抽象角色*/ interface Subject { public void request(String param); } /*目标角色*/ class RealSubject implements Subject{ @Override public void request(String param) { System.out.println("真实请求成功"); } } /** * public Object invoke(Object proxy, Method method, Object[] args) throws Throwable * 第一个参数是代理对象,第二个参数是目标方法,第三个参数是目标方法参数 */ class ProxyHandler implements InvocationHandler{ Object target; public ProxyHandler(Object target) { this.target=target; } public void before(String param) throws Throwable{ if(param.equals("abc")) throw new IllegalArgumentException(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before((String)args[0]); return method.invoke(target, args); } }
参考:http://www.cnblogs.com/silverLee/archive/2010/02/05/1664577.html