设计模式之代理模式(全面讲解)

      设计模式是一套被反复使用,多数人知晓,通过分类编目的,代码设计的总结,也能够说是前人的智慧结晶。学习设计模式能让咱们对一些应用场景使用相同的套路达到很好的效果,我会不定时更新一些本身对设计模式的理解的文章,从定义,实现,应用场景来讲说设计模式,今天我要说的对象是代理模式java

  一:定义   设计模式

    代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。代理模式是经常使用的结构型设计模式之一,当没法直接访问某个对象或不适合直接访问某个对象时能够经过一个代理对象来间接访问,代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即经过代理对象访问目标对象.这样作的好处是:能够在目标对象实现的基础上,加强额外的功能操做,即扩展目标对象的功能。这么作也服务开闭原则(对扩展开放对修改关闭)的要求。代理模式的关键点是:代理对象会调用被代理对象,代理对象对被代理对象的功能作了扩展。框架

    打个比方,咱们想要购买国外的某些商品,因为各类成本问题,直接去一趟国外不划算,因而咱们找了代购帮咱们购买,这里的代购帮咱们到国外的实体店完成了购买的动做,他就是实体店的代理,而实体店是被代理,而咱们和代购直接的沟通交涉,至关因而对被代理功能的扩展,而这一步是在咱们和代理直接完成,不会影响被代理的商店ide

 

  二:实现函数

    从实现上来讲,代理模式能够分为静态,动态代理和子类代理工具

    静态代理:静态代理在使用时,须要定义接口或者父类,被代理对象与代理对象一块儿实现相同的接口或者是继承相同父类,所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就肯定了。下面展现代码实现性能

    //定义接口学习

    interface UserDao{测试

        void save();
    }
    //被代理类实现接口
    class UserService implements UserDao{
     @Override
     public void save() {
      System.out.println("这是须要被代理的保存方法");
     }
    }

    //代理类代理相关的方法
    class UserDaoProxy implements UserDao{
      //在代理类中引用被代理类,这里只是使用最简单的方法
     private UserDao iUserDao;
    public UserDaoProxy(UserDao iUserDao){
    this.iUserDao=iUserDao;
    }
      //引用并扩展被代理类的方法
    @Override
    public void save() {
     System.out.println("这里编写须要扩展的内容");
    iUserDao.save();
    System.out.println("保存成功或者失败以后的操做");
  }

  //测试一下
public static void main(String[] df){

UserDaoProxy proxy=new UserDaoProxy(new UserService()); proxy.save();
}
}  
    动态代理:代理对象是动态生成的,不须要实现父类接口
      动态的生成一个对象,很天然的就想到反射。JDK中有动态生成代理的包(java.lang.reflect.Proxy),是专门为建立动态代理对象存在的,它的内部实现是使用了反射技术,JDK实现代理只须要使用newProxyInstance方法,可是该方法须要接收三个参数,完整的写法是: static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为:        ● ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的       ● Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型       ● InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法做为参数传入。
    这里使用一个工厂类建立动态代理对象来代替上面的代理对象,其余方法不变
    class ProxyFactory{      public static Object getProxyInstance(Object target){       return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {       @Override        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {          System.out.println("这是代理对象扩展的内容");         Object object=method.invoke(target,args);        return object;       }        });     }
      //测试一下
    public static void  main(String[] df){

UserDao object=(UserDao)ProxyFactory.getProxyInstance(new UserService());
object.save();
}
    }
      子类代理:
          上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,可是有时候目标对象只是一个单独的对象,并无实现任何的接口,这个时候就可使用以目标对象子类的方式类实现代理,这种方法就叫作:Cglib代理

        Cglib代理,也叫做子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.

        ● JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,若是想代理没有实现接口的类,就可使用Cglib实现.
        ● Cglib是一个强大的高性能的代码生成包,它能够在运行期扩展java类与实现java接口.它普遍的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
        ● Cglib包的底层是经过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,由于它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
          Cglib子类代理实现方法:
        1.须要引入cglib的jar文件,可是Spring的核心包中已经包括了Cglib功能,因此直接引入pring-core-3.2.5.jar便可.
        2.引入功能包后,就能够在内存中动态构建子类
        3.代理的类不能为final,不然报错
        4.目标对象的方法若是为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.this

         //被代理对象,没有实现任何接口
      class UserDao {

              public void save() {
                System.out.println("----已经保存数据!----");
              }
      }

      class ProxyFactory implements MethodInterceptor{

          //给目标对象建立一个代理对象
          public Object getProxyInstance(Object target){
            //1.工具类
            Enhancer en = new Enhancer();
            //2.设置父类
            en.setSuperclass(target.getClass());
            //3.设置回调函数
            en.setCallback(this);
            //4.建立子类(代理对象)
            return en.create();
          }

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
              System.out.println("这是须要扩展的内容...");

            //执行目标对象的方法
            Object returnValue = method.invoke(target, args);

              System.out.println("这是须要扩展的内容...");

            return returnValue;
        }

        //测试一下

        public static void main(String[] arg){  

          //被代理对象
          UserDao target = new UserDao();

          //代理对象
          UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();

          //执行代理对象的方法
          proxy.save();

        }
      }

 

  三:应用场景

    从应用场景来讲,代理模式能够分为远程代理,缓冲代理,智能引用代理,虚拟代理,保护代理等等

    (1) 当客户端对象须要访问远程主机中的对象时可使用远程代
    (2) 当须要用一个消耗资源较少的对象来表明一个消耗资源较多的对象,从而下降系缩短运行时间时可使用虚拟代理,例如一个对象须要很长时间才能完成加
    (3) 当须要为某一个被频繁访问的操做结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可使用缓冲代理。经过使用缓冲代理,系统无须在客户端每一次访问时都从新执行操做,只需直接从临时缓冲区获取操做结果便可。
    (4) 当须要控制对一个对象的访问,为不一样用户提供不一样级别的访问权限时可使用保护代理。
    (5) 当须要为一个对象的访问(引用)提供一些额外的操做时可使用智能引用代理。

相关文章
相关标签/搜索