zoukankan      html  css  js  c++  java
  • 代理模式

    什么是代理模式

      简单说即是不改变源码的情况下,实现对目标对象功能扩展

        举个例子:比如有个歌手对象叫Singer,这个对象有一个唱歌方法叫sing() ,假如你希望,通过你的某种方式生产出来的歌手对象,在唱歌前后还要想观众问好和答谢,也即对目标对象Singer的sing方法进行功能扩展。但是往往你又不能直接对源代码进行修改

      这时就需要用到java的代理模式

    代理模式的主要优点有:

    • 代理模式在客户端与目标对象之间起到一个中介作用保护目标对象的作用;
    • 代理对象可以扩展目标对象的功能
    • 代理模式能将客户端与目标对象分离,在一定程度上降低系统的耦合度

    Java的三种代理模式

     public class Singer{
         public void sing(){
             System.out.println("唱一首歌");
         }  
     }

      1静态代理模式:

    public interface ISinger {
          void sing();
      }
      
      /**
       *  目标对象实现了某一接口
       */
      public class Singer implements ISinger{
          public void sing(){
             System.out.println("唱一首歌");
         }  
     }
     
     /**
      *  代理对象和目标对象实现相同的接口
      */
     public class SingerProxy implements ISinger{
         // 接收目标对象,以便调用sing方法
         private ISinger target;
         public UserDaoProxy(ISinger target){
             this.target=target;
         }
         // 对目标对象的sing方法进行功能扩展
         public void sing() {
             System.out.println("向观众问好");
             target.sing();
             System.out.println("谢谢大家");
         }
     }
    View Code

      测试:

    /**
       * 测试类
       */
      public class Test {
          public static void main(String[] args) {
              //目标对象
              ISinger target = new Singer();
              //代理对象
             ISinger proxy = new SingerProxy(target);
             //执行的是代理的方法
             proxy.sing();
         }
     }
    View Code

     总结:建一个代理类SingerProxy,继承了对象ISinger接口并实现了其中的方法。只不过这种实现特意包含了目标对象的方法,正是这种特征使得看起来像是“扩展”了目标对象的方法。假使代理对象中只是简单地对sing方法做了另一种实现而没有包含目标对象的方法,也就不能算作代理模式了。所以这里的包含是关键。

      缺点:代理对象必须提前写出,如果接口层发生了变化,代理对象的代码也要进行维护。如果能在运行时动态地写出代理对象,不但减少了一大批代理类的代码,也少了不断维护的烦恼,不过运行时的效率必定受到影响。

      2动态代理模式(也叫JDK代理)

     public interface ISinger {
          void sing();
      }
      
      /**
       *  目标对象实现了某一接口
       */
      public class Singer implements ISinger{
         public void sing(){
             System.out.println("唱一首歌");
         }  
     }

      java底层封装了实现细节 调用Proxy类的静态方法newProxyInstance即可,该方法会返回代理类对象  static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

    接收的三个参数依次为:

    • ClassLoader loader指定当前目标对象使用类加载器,写法固定
    • Class<?>[] interfaces标对象实现的接口类型,写法固定
    • InvocationHandler h事件处理接口,需传入一个实现类,一般直接使用匿名内部类

    测试代码

    public class Test{
          public static void main(String[] args) {
        Singer target = new Singer();
              ISinger proxy  = (ISinger) 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 returnValue = method.invoke(target, args);
                             System.out.println("谢谢大家");
                             return returnValue;
                         }
                     });
             proxy.sing();
         }
     }

    总结:由于java封装了newProxyInstance这个方法的实现细节,所以使用起来才能这么方便

    来源于:传送门

  • 相关阅读:
    POJ3662 Telephone Lines (dijkstra+二分)
    Codeforces Round #618 (Div. 2)A. Non-zero
    Codeforces Round #618 (Div. 2)C. Anu Has a Function
    洛谷P1060开心的金明(滚动数组优化)
    洛谷P1006传纸条
    Spring Boot中以代码方式配置Tomcat
    js常用方法总结(以后遇到再进一步总结)
    localStorage的使用
    巧用Ajax的beforeSend 提高用户体验
    四种会话跟踪技术
  • 原文地址:https://www.cnblogs.com/JonaLin/p/12718496.html
Copyright © 2011-2022 走看看