资讯专栏INFORMATION COLUMN

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

233jl / 3326人阅读

摘要:面试题增强一个对象的方法的三种方式继承使用这种方式必须满足的条件是被增强的方法的所在类能被继承,并且这个对象已经明确知道。所以创建一个类继承重写了父类的方法增强了,变成飞了。。。

面试题:增强一个对象的方法的三种方式 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"%>




Insert title here


    
用户名:

用户名:

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


    MyFilter
    com.itzhouq.filter.MyFilter


    MyFilter
    /*

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不在乱码。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74395.html

相关文章

  • 一道面试引发思考

    摘要:下面我们来使用面向对象类图这里就不再画了首先面试题中所提到的我们都可以看成类,比如停车场是一个类吧,它里面的车位是一个类吧,摄像头,屏幕。。。 以下是某场的一道面试题(大概): 1、一个停车场,车辆入场时,摄像头记录下车辆信息2、屏幕上显示所接收的车辆的信息情况(车牌号)以及各层车位的车位余量3、停车场一共四层车位,其中的三层都为普通车位,还有一层为特殊车位(体现在停车计费价格上面的不...

    Apollo 评论0 收藏0
  • 一道面试引发思考

    摘要:下面我们来使用面向对象类图这里就不再画了首先面试题中所提到的我们都可以看成类,比如停车场是一个类吧,它里面的车位是一个类吧,摄像头,屏幕。。。 以下是某场的一道面试题(大概): 1、一个停车场,车辆入场时,摄像头记录下车辆信息2、屏幕上显示所接收的车辆的信息情况(车牌号)以及各层车位的车位余量3、停车场一共四层车位,其中的三层都为普通车位,还有一层为特殊车位(体现在停车计费价格上面的不...

    soasme 评论0 收藏0
  • 一道面试引发思考

    摘要:下面我们来使用面向对象类图这里就不再画了首先面试题中所提到的我们都可以看成类,比如停车场是一个类吧,它里面的车位是一个类吧,摄像头,屏幕。。。 以下是某场的一道面试题(大概): 1、一个停车场,车辆入场时,摄像头记录下车辆信息2、屏幕上显示所接收的车辆的信息情况(车牌号)以及各层车位的车位余量3、停车场一共四层车位,其中的三层都为普通车位,还有一层为特殊车位(体现在停车计费价格上面的不...

    Backache 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<