面试题:增强一个对象的方法的三种方式

栏目: Java · 发布时间: 6年前

面试题:增强一个对象的方法的三种方式

1. 继承

  • 使用这种方式必须满足的条件是:被增强的方法的所在类能被继承,并且这个对象已经明确知道。
  • 举例:
  • 有一个接口Person,里面有一个方法run()

    package com.itzhouq.demo1;
    
    public interface Person {
        public void run();
    }
  • 类NormalPerson实现了这个接口Person

    package com.itzhouq.demo1;
    
    public class NormalPerson implements Person {
    
        @Override
        public void run() {
            System.out.println("走.......");
        }
    }
  • 现在的需求是,使用继承方式增强NomalPerson中的方法run()
  • 这里需要被增强的方法是run(),所在的类NomalPerson可以被继承并且已经明确。
  • 所以创建一个类Superson继承NormalPerson

    package com.itzhouq.demo1;
    
    public class Superson extends NormalPerson {
        //重写了父类NormalPerson的方法
        @Override
        public void run() {
            super.run();
            System.out.println("增强了,变成飞了。。。");
        }
    }
  • 类Superson通过对父类NormalPerson的run()方法进行重写,实现对run()方法的增强。
  • 测试
package com.itzhouq.demo1;
  
  import org.junit.Test;
  
  /*
   * 增强一个对象的方法之一:继承方式
   */
  public class Demo {
      
      @Test
      public void test() {
          NormalPerson p = new NormalPerson();
          p.run();//走.......
      }
      
      //需求:对普通人的run方法进行增强,由走变成飞----增强一个对象的方法
      //用继承来实现需求:创建一个类继承NormalPerson
      @Test
      public void test2() {
          Superson superson = new Superson();
          superson.run();
  //        走.......
  //        增强了,变成飞了。。。
      }
      
  }

2. 装饰者模式

  • 装饰者模式实现对方法的增强,不需要知道被增强的方法run()所在的类是哪个类,只需要知道这个类实现了哪个接口即可。
  • 条件:

    • 装饰者和被装饰者需要实现同一个类
    • 装饰者有被装饰者的引用
  • 接口:

    package com.itzhouq.demo2;
    
    public interface Person {
        public void run();
    }
  • 需要被增强的方法run()

    package com.itzhouq.demo2;
    
    public class NormalPerson implements Person {
    
        @Override
        public void run() {
            System.out.println("走.......");
        }
    }
  • 这里被装饰者就是run()方法所在的类
  • 创建一个装饰者类,实现run()所在类,实现的接口Person

    package com.itzhouq.demo2;
    
    public class Superson implements Person {
        //被装饰者的引用
        private NormalPerson p;
        public Superson(NormalPerson p) {
            this.p = p;
        }
        
        @Override
        public void run() {
            //这个是被装饰者以前的方法
            p.run();
            //增强
            System.out.println("增强了,变成飞。。。。");
        }
    }
  • 测试
package com.itzhouq.demo2;
  
  import org.junit.Test;
  /*
   * 增强一个对象的方法之二:装饰者方式
   */
  public class Demo {
      
      @Test
      public void test() {
          NormalPerson p = new NormalPerson();
          p.run();//走.......
      }
      
      //需求:对普通人的run方法进行增强,由走变成飞
      //假装不知道接口的实现类NormalPerson,但是要对普通人的run方法进行增强
      //不知道实现类就无法使用继承的方式进行增强
      //使用装饰者解决这样的问题:
          //条件1:装饰者()和被装饰者()实现同一个接口Person
          //条件2:装饰者里面有被装饰者的引用         在我出生的时候,你把你给我,我对你进行增强
      
      @Test
      public void test2() {
          NormalPerson p = new NormalPerson();
          Superson superson = new Superson(p);
          superson.run();
  //        走.......
  //        增强了,变成飞。。。。
  
      }
  }

3. 动态代理

  • 通过一张图回顾动态代理

    面试题:增强一个对象的方法的三种方式

  • 动态代理的条件:必须知道要被代理的类/对象是谁,这里要被代理的类是NoemalPerson

    Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interface, InvocationHander h);
    //返回一个指定接口的代理类实现
  • 接口person,这里再加一个方法sleep

    package com.itzhouq.demo3;
    
    public interface Person {
        public void run();
        public String sleep();
    }
  • 实现类NomalPerson

    package com.itzhouq.demo3;
    
    public class NormalPerson implements Person {
    
        @Override
        public void run() {
            System.out.println("走.......");
        }
    
        @Override
        public String sleep() {
            System.out.println("睡觉了。。。");
            return "sleep";
        }
    }
  • 使用动态代理增强
package com.itzhouq.demo3;
  
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
  
  import org.junit.Test;
  
  public class Demo {
      @Test
      public void test() {
          NormalPerson p = new NormalPerson();
          p.run();//走.......
      }
      
      //需求:使用动态代理的方式对普通人进行增强
      //JDK提供的类和方法可以给咱们动态的生成代理对象/增强对象
      
      /*
       * 参数概述:固定的
       *     参数1:和要被增强的对象,一样的,类加载器
       *     参数2:和要被增强的对象一样的接口
       *             1 根据指定的传递接口返回一个该接口下的实例
       *             2 传递的接口里面的方法就是可以被增强的所有方法
       *     参数3:所有的增强业务的逻辑实现(方法)
       */
      @Test
      public void test1() {
          NormalPerson p = new NormalPerson();
          Person proxyPerson = (Person) Proxy.newProxyInstance(
                  p.getClass().getClassLoader(), 
                  p.getClass().getInterfaces(),
                  new InvocationHandler() {
                      
                      /*
                       *     参数概述:固定的
                       *     参数1:不用管,永远是固定值     代理对象的类型
                       *     参数2:要被增强的方法
                       *     参数3:要被增强的方法运行过程中需要的参数
                       */
                      @Override    //invoke里面是所有的增强业务的逻辑代码
                      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                          //让以前的方法执行
                              //参数1:本身应该执行这个方法的对象
                              //参数2:执行这个方法需要的参数
                          Object value = method.invoke(p, args);
                          //原来方法的返回值
                          System.out.println(value);
                          // 写增强业务逻辑
                          System.out.println("增强了,变成飞了。。。");
                          //最终的返回值,谁调用返回给谁
                          return "abcd";
                      }
                  });
          proxyPerson.run();//执行接口中的每一个需要增强的方法,invoke都会执行一遍,执行的内容就是针对该方法的增强
  //        走.......
  //        增强了,变成飞了。。。
          String value = proxyPerson.sleep();
          System.out.println(value);
  //        睡觉了。。。
  //        sleep
  //        增强了,变成飞了。。。
  //        abcd
      }
  }

4. 扩展:使用动态代理方式统一字符集编码

  • 新建Web项目,新建一个index.jsp。在JSP中写两个表单,分别为post和get方式提交。后台通过Servlet接收到前台输入的username,打印在控制台会乱码。
  • JSP

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <form action="${pageContext.request.contextPath }/sd1" method="get">
            用户名:<input type="text" name="username">
            <input type="submit" value="提交">
        </form>
        
        <hr>
        
        <form action="${pageContext.request.contextPath }/sd1" method="post">
            用户名:<input type="text" name="username">
            <input type="submit" value="提交">
        </form>
    </body>
    </html>
  • Servlet

    package com.itzhouq.web;
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class ServletDemo1 extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String username = request.getParameter("username");
            System.out.println(username);
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
    }
  • 为解决这个问题使用过滤器,在过滤器中使用动态代理方式解决
  • 新建一个过滤器MyFilter.java,并在xml文件中配置过滤的资源为全部资源
  • web.xml

    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.itzhouq.filter.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
  • MyFilter

    package com.itzhouq.filter;
    
    import java.io.IOException;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    
    public class MyFilter implements Filter {
        public MyFilter() {
        }
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            //要增强的方法:request.getparameter
            //被代理的对象:request
            HttpServletRequest request = (HttpServletRequest)req;
            
            //动态的生成代理对象
            HttpServletRequest hsr = (HttpServletRequest) Proxy.newProxyInstance(
                    request.getClass().getClassLoader(), 
                    request.getClass().getInterfaces(), 
                    new InvocationHandler() {
                        
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //1. 判断是否是要增强的方法getParameter
                            if("getParameter".equals(method.getName())) {
                                //知道getParameter使用的是哪个提交方式
                                String m = request.getMethod();
                                //判断是get还是post
                                if("get".equalsIgnoreCase(m)) {
                                    //    以前方法调用后的乱码
                                    String s = (String)method.invoke(request, args);
                                    // 增强---解决乱码
                                    s = new String(s.getBytes("iso8859-1"),"utf-8");
                                    return s;
                                }
                                if("post".equalsIgnoreCase(m)) {
                                    request.setCharacterEncoding("utf-8");
                                    return method.invoke(request, args);
                                }
                            }
                            
                            //    如果是别的方法
                            return method.invoke(request, args);
                        }
                    });
            
            chain.doFilter(hsr, response);
        }
    
        public void init(FilterConfig fConfig) throws ServletException {
        }
    }
  • 后台Servlet接收到的username不在乱码。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learning jQuery

Learning jQuery

Jonathan Chaffer、Karl Swedberg / Packt Publishing / 2007-7-7 / GBP 24.99

jQuery is a powerful JavaScript library that can enhance your websites regardless of your background. In this book, creators of the popular jQuery learning resource, learningquery.com, share the......一起来看看 《Learning jQuery》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试