23中设计模式——代理模式

代理模式

一、定义

1、 什么是代理模式?

为其他对象提供一种代理以控制对这个对象的访问。(就是用用一个中间者,让被代理的对象能够访问其他对象。)

实例:就像房产中介就是代理对象,买房的你就是被代理对象,卖房则为其他对象。买房的你被代理,只需要实现交钱手续,其他的小手续则有房产中介为你代劳。

2、UML图

二、实例
1、静态代理

静态代理要求被代理类和代理类实现同一个接口或者类。

重点:在编译期间确定代理对象,在程序运行前就已经确定代理类.class文件已经存在。比如:代理对象实例化时,通过代理对象类的构造方法将被代理对象传入。

譬如:(静态代理这段代码很像装饰者模式)

接口:User

package com.golf.proxy;

//代理类和被代理类的公共接口
public interface User {
  public void save();
}

被代理类:UserDao

package com.golf.proxy;

//代理类和被代理类的公共接口
public interface User {
  public void save();
}

 

代理类:ProxyUser

package com.golf.proxy;

//代理类
public class ProxyUser implements User{
  public User user;
  public ProxyUser(User user){ //通过构造方法将
      this.user = user;
  }
  @Override
  public void save() {
      System.out.println("开始事务");
      user.save();
      System.out.println("结束事务");
  }
}

 

静态代理的总结:

优点:可以在不更改原有类的基础上,增加功能。符合开放-封闭原则。(感觉贼像装饰者模式)

缺点:

代理类和被代理类实现相同的接口,会让代码重复很多。同时,如果接口增加一个新的方法,代理类和被代理类都需要实现这个方法,代码的维护变得复杂。

2、动态代理(JDK代理)

1、动态代理的代理类不需要实现接口。

2、代理对象的生成是通过JDK的API动态的在内存中构建对象(通过构造方法,将指定的被代理对象传入。通过JDK的代理类所在的包Java.lang.reflect.Proxy)

3、动态代理只需要实现newProxyInstance方法。

 static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

该方法是静态方法,在对应的ProxyFactory中,导入JDK的Proxy类然后直接调用变形。

三个参数分别代表的意义

1、ClassLoader loader : 被代理类的对象。 被代理对象.getClass().getClassLoader();获得被代理对象

2、Class<?> interface : 是公共的接口。 公共接口.getClass().getInterface() 获得接口

3、InvocationHandler h:调用处理器

在动态代理中,除了代理类不同其他的都一样,被代理类一样需要实现接口。在动态代理中,创建ProxyFactory类,在通过JDK的newProxyInstance方法去创建对应的代理类。

package com.golf.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//动态创建代理对象
//动态代理对象无需实现公共接口,根据jdk的api在内存中创建相应的被代理对象
public class ProxyFactory {
  public User user;
  public ProxyFactory(User user){ //通过构造方法将被代理类传入
      this.user = user;
  }
   
  //此方法用Object进行返回,不清楚代理类最后返回的类型,记得在客户端中相应的转换。
  public Object getInstanceProxy(){
      return Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(),
              new InvocationHandler() {
                  @Override
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                      System.out.println("开始事务");
                      Object invoke = method.invoke(user, args);
                      System.out.println("结束事务");
                      return invoke;
                  }
              }
      );
  }

}

测试类:

package com.golf.proxy;

public class ClientProxy {
  public static void main(String[] args) {
      User user = new UserDao();
      ProxyFactory proxyFactory = new ProxyFactory(user);
      //proxyFactory类的getInstance方法 返回的是Object型,需要根据自己被代理类的类型进行转换
      User instanceProxy = (User)proxyFactory.getInstanceProxy();
      System.out.println(instanceProxy.getClass());
      instanceProxy.save();
  }
}

动态代理的好处:

相对于静态代理而言,动态代理的代理类无需实现接口,但是被代理类需要实现接口。

3、Cglib代理

Cglib代理的好处在于他不需要代理类和被代理类实现接口,只是一个单独的对象。通过构建被代理类子类的方式实现代理。

定义:Cglib代理(子类代理),在内存中构建一个子类对象从而实现对代理对象功能的扩展。

注意点:

1、需要用到Cglib包,Spring-Core的包已经整合,所以只需要导入Spring-Core包就行。

2、Cglib是一个强大的高性能代码生成包,他可以在运行期扩展Java类和实现Java接口,在Spring框架AOP里面有进行使用,提供方法的Interception(拦截)。

3、Cglib包的底层通过字节码处理框架ASM来转换字节码生成新的子类

4、被代理的类不能被final修饰,被代理类的方法如果被final、static所修饰便不会被拦截器拦截,因此也不会生效。

package com.golf.CglibProxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
//对UserDao在内存中动态的创建了一个子类对象
//代理工厂类
public class ProxyFactory implements MethodInterceptor{
  private UserDao userDao; //被代理对象

  public ProxyFactory(UserDao userDao){
      this.userDao = userDao;
  }

  //创建一个代理对象
  public Object getInstance(){
      //1、导入JDK中Enhancer工具类
      Enhancer enhancer = new Enhancer();
      //2、设置父类
      enhancer.setSuperclass(userDao.getClass());
      //3、设置回调函数
      enhancer.setCallback(this);
      //4、创建代理对象(子类)
      return enhancer.create();
  }


  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
      System.out.println("开始事务");
      Object invoke = method.invoke(userDao, objects);
      System.out.println("结束事务");
      return invoke;
  }
}

测试类:

/**
* 测试类
*/
public class App {

  @Test
  public void test(){
      //目标对象
      UserDao target = new UserDao();

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

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



ps:由于是新学设计模式,很多的知识借鉴他人,可能有些观点很可怜。若有错误,希望指出!谢谢!!

猜你喜欢

转载自www.cnblogs.com/bm654/p/11943116.html