设计模式--静态代理模式和动态代理模式原理及实现

代理模式(委托模式)

为其他对象提供一种代理以控制对这个对象的访问。引入代理对象来间接访问目标对象

代理模式

代理模式优点:

  • 职责清晰:真实的角色就是实现实际的业务逻辑,不需关心其他非本职责的事务
  • 高扩展性:代理类可以在不做任何修改的情况下继续使用
  • 智能化:动态代理演示

代理模式缺点:

  1. 在客户端和真实对象之间添加了代理,会造成请求的处理速度变慢
  2. 实现代理模式比较复杂,需要额外的工作

代理模式的扩展:

  1. 普通代理

    客户端只能访问代理角色,而不能直接访问真实角色。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Client {
    public static void main(String[] args){
    //屏蔽了GamePlayer的真实角色访问
    GamePlayerProxy gamePlayerProxy = new GamePlayerProxy("wxy");
    gamePlayerProxy.login("wxy","124");
    gamePlayerProxy.killBoss();
    gamePlayerProxy.upgrade();
    }
    }

    Client只是调用了GamePlayerProxy代理角色,而不知道真实角色是谁。非常适合扩展性要求较高的场景。

  2. 强制代理

    通过真实角色来找到代理角色,否则不能访问。由真实角色来管理代理角色。不允许直接访问真实角色

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class Client {
    public static void main(String[] args){
    //必须是真实角色的代理对象才可以使用
    IGamePlayer gamePlayerProxy = new GamePlayer("wxy").getProxy();
    //直接生成代理对象无效
    //GamePlayerProxy gamePlayerProxy = new GamePlayerProxy(new GamePlayer("wzr5"));
    gamePlayerProxy.login("wxy","124");
    gamePlayerProxy.killBoss();
    gamePlayerProxy.upgrade();
    }
    }
  3. 代理是有个性的

    一个类可以实现多个接口,完成不同任务的整合。代理类不仅可以实现主题接口,也可以实现其他接口完成不同的任务。

  4. 动态代理

    不需要显式实现与目标对象类相同的接口,将这种实现推迟到程序运行时由JVM实现。

    原理:通过Java反射机制的method.invoke()调用动态代理类对象方法,从而自动调用目标对象的方法。

    优点:1. 只需要一个代理类就可以解决创建多个静态代理的问题,避免重复代码。2. 更加灵活

    缺点:1. 效率低 需要通过反射机制,间接调用目标对象方法 2.应用场景局限只能针对接口创建代理类,即只能动态代理实现了接口的类

    应用场景:

    • 需要代理对象数量较多的情况下使用

    • AOP-面向切面编程

      可以通过预编译的方式在运行期动态代理实现程序功能的统一维护,有效降低业务之间的耦合度,提供程序的可用性并提高了开发的效率。开发中主要用在日志收集,性能分析等。

    使用方法:

    1. 声明调用代理类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      public class GamePlayIH<T> implements InvocationHandler {
      //被代理实例
      T obj ;

      public GamePlayIH(T _obj) {
      this.obj = _obj;
      }

      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      Object result = method.invoke(this.obj, args);
      return result;
      }
      }
    2. 声明目标对象类的抽象接口

      1
      2
      3
      4
      5
      6
      7
      public interface IGamePlayer {
      void login(String user, String pwd);

      void killBoss();

      void upgrade();
      }
    3. 声明目标对象类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      public class GamePlayer implements IGamePlayer {
      private String name = "";

      public GamePlayer(String _name) {
      this.name = _name;
      }

      @Override
      public void login(String user, String pwd)
      {
      System.err.println("登录名为:" + user + " 用户名为:" + this.name + "登录游戏");
      }

      @Override
      public void killBoss()
      {
      System.err.println(this.name + "打Boss");
      }

      @Override
      public void upgrade()
      {
      System.err.println(this.name + "升级了");
      }
      }
    4. 通过动态代理对象,调用目标方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      public class Client {
      public static void main(String[] args) {
      //创建目标对象
      IGamePlayer player = new GamePlayer("wxy");
      //创建调用处理对象
      InvocationHandler handler = new GamePlayIH<>(player);
      //指定产生代理对象的类加载器
      ClassLoader cl = player.getClass().getClassLoader();
      //创建动态代理对象
      IGamePlayer gamePlayerProxy = (IGamePlayer) Proxy.newProxyInstance(cl, new Class[]{IGamePlayer.class}, handler);
      //调用动态代理对象方法
      gamePlayerProxy.login("wxy", "124");
      gamePlayerProxy.killBoss();
      gamePlayerProxy.upgrade();
      }
      }

Proxy:提供用于创建动态代理类和实例的静态方法,并且还是创建出代理类的超类。

InvocationHandler:调用处理器接口,自定义invoke(),用于实现对真正委托类的代理方法。生成动态代理类实际调用的是invoke()