四、代理模式

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

http://www.jianshu.com/p/c3add1ef26e2

http://layznet.iteye.com/blog/1182924

posted @ 2017-09-26 11:33  国境之南时代  阅读(169)  评论(0编辑  收藏  举报