今天有人问我怎么增强一个类的功能。博客刚好没东西,今天就讲讲增强类。

增强的手段有三种类型:

1、继承或者实现接口:特点是被增强对象不能变,增强的内容不能变。

2、装饰着模式:特点是被增强对象可变,但增强内容不可变。

3、动态代理:特点是被增强对象可变,增强内容可变。

下面是三种对a对象进行增强的手段:
 继承:AA类继承a对象的类型:A类,然后重写fun1()方法,其中重写的fun1()方法就是被增强的方法。但是,继承必须要知道a对象的真实类型,然后才能去继承。如果我们不知道a对象的确切类型,而只知道a对象是IA接口的实现类对象,那么就无法使用继承来增强a对象了;
 装饰者模式:AA类去实现a对象相同的接口:IA接口,还需要给AA类传递a对象,然后在AA类中所有的方法实现都是通过代理a对象的相同方法完成的,只有fun1()方法在代理a对象相同方法的前后添加了一些内容,这就是对fun1()方法进行了增强;
 动态代理:动态代理与装饰者模式比较相似,而且是通过反射来完成的。

详解:

1、继承,java是面向对象的语言,继承机制使他的可扩展性大大增强,我们可以通过继承方式对现有类进行扩展增强。子类继承父类之后可以获得父类所有的公共方法,子类可以进行重写等操作,这种方式简便易学,但是随之而来的是代码的耦合性大大的增强,不利于后期的维护,所以对于继承这种方法,谨慎使用。

2、装饰者设计模式,设计模式是java编程的重要组成部分,确切的说不仅仅是Java,几乎所有的高级编程语言都多多少少会涉及到编程模式。当然想要完全理解设计模式,单纯学习一门语言是完全不够的。百度百科中的解释为:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。java的IO流就是标准的装饰者模式,在这里我们拿出java中的两个类做解释InputStream和BufferedInputStream,两个类分别为字节输入流和字节缓冲输入流,简单来说缓冲流就是字节流的强化版,使用的模式就是装饰者模式,我们可以看到BufferedInputStream的构造方法中BufferedInputStream(InputStream
in)
字节流就是作为参数输入,这样缓冲流中可以通过输入的字节流对象来调用字节流中的所有的方法,同时不会妨碍缓冲流的私有方法,这就是比较经典的装饰者强化。

下面举个例子说明:

需求:处理GET请求参数编码问题,需要在Filter中放行时,把request对象给“调包”了,也就是让目标Servlet使用我们“调包”之后的request对象。这说明我们需要保证“调包”之后的request对象中所有方法都要与“调包”之前一样可以使用,并且getParameter()方法还要有能力返回转码之后的参数。这可能让你想起了“继承”,但是这里不能用继承,而是“装饰者模式(Decorator
Pattern)”!

解决方法:对request对象进行增强的条件,刚好符合装饰者模式的特点!因为我们不知道request对象的具体类型,但我们知道request是HttpServletRequest接口的实现类。这说明我们写一个类EncodingRequest,去实现HttpServletRequest接口,然后再把原来的request传递给EncodingRequest类!在EncodingRequest中对HttpServletRequest接口中的所有方法的实现都是通过代理原来的request对象来完成的,只有对getParameter()方法添加了增强代码!
JavaEE已经给我们提供了一个HttpServletRequestWrapper类,它就是HttpServletRequest的包装类,但它没做任何的增强!你可能会说,写一个装饰类,但不做增强,其目的是什么呢?使用这个装饰类的对象,和使用原有的request有什么分别呢?HttpServletRequestWrapper类虽然是HttpServletRequest的装饰类,但它不是用来直接使用的,而是用来让我们去继承的!当我们想写一个装饰类时,还要对所有不需要增强的方法做一次实现是很心烦的事情,但如果你去继承HttpServletRequestWrapper类,那么就只需要重写需要增强的方法即可了。

EncodingRequest代码:

    /**
* <p>类名称 EncodingRequest </p>
* <p>类描述 装饰者模式:
* 增强request的getParameter方法,使其编码格式为utf-8
* </p>
* @author 裴健
* @date 2017年3月22日 下午1:53:06
*/
public class EncodingRequest extends HttpServletRequestWrapper{ private HttpServletRequest request;
public EncodingRequest(HttpServletRequest request) {
super(request);
this.request=request;
} @Override
public String getParameter(String name) {
String value = request.getParameter(name);
try {
value=new String(value.getBytes("iso-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return value;
} }

这里是将get请求的request对象对getParameter()方法增强了,直接将“iso-8859-1”的编码改为“utf-8”的编码。

3、代理模式,代理类模式理解起来会比装饰者设计模式更加难,因为这个涉及到反射的原理。学习代理模式最终是学习AOP(面向切面编程),它与装饰者模式有点相似,它比装饰者模式还要灵活!

下面举个例子说明:

需求:(1)定义一个服务员接口

// 服务员
public interface Waiter {
// 服务
public void serve();
}

(2)一个男服务员的类并实现服务员接口。男服务员有个方法是服务。

    public class ManWaiter implements Waiter {
public void serve() {
System.out.println("服务中...");
}
}

现在想让男服务员在服务的时候有礼貌,需要在服务的方法前后加上礼貌用语。此时会想到修改代码实现。如果每次增强一个方法都去修改源代码,通俗点说,显得太low了。这里就需要动态代理增强这个“服务员”。

解决代码:

    public class Demo {
@Test
public void fun1() {
Waiter manWaiter = new ManWaiter();//目标对象
/*
* 给出三个参数,来创建方法,得到代理对象
*/
ClassLoader loader = this.getClass().getClassLoader();
Class[] interfaces = {Waiter.class};
InvocationHandler h = new WaiterInvocationHandler(manWaiter);//参数manWaiter表示目标对象
// 得到代理对象,代理对象就是在目标对象的基础上进行了增强的对象!
Waiter waiterProxy = (Waiter)Proxy.newProxyInstance(loader, interfaces, h); waiterProxy.serve();//前面添加“您好”, 后面添加“再见”
}
} class WaiterInvocationHandler implements InvocationHandler {
private Waiter waiter;//目标对象 public WaiterInvocationHandler(Waiter waiter) {
this.waiter = waiter;
} public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("您好!");
this.waiter.serve();//调用目标对象的目标方法
System.out.println("再见!");
return null;
}
}

Java中增强一个类的几种方法的更多相关文章

  1. Java中获取键盘输入值的三种方法

    Java中获取键盘输入值的三种方法     Java程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值 ...

  2. java中调用dll文件的两种方法

    一中是用JNA方法,另外是用JNative方法,两种都是转载来的, JNA地址:http://blog.csdn.net/shendl/article/details/3589676   JNativ ...

  3. Java中的一个类怎么调用另一个类中的方法

    如果另一个类中的那个方法是私有的话,就不能直接调用到,如果是其他类型的话看情况,如果是静态的(static)话,直接用类名可以调用到,如果是非静态的,就需要利用另一个类的实例(也就是用那个类生成的对象 ...

  4. Java中遍历Map集合的四种方法

    在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...

  5. Java中spring读取配置文件的几种方法

    Spring读取配置XML文件分三步: 一.新建一个Java Bean: package springdemo; public class HelloBean { private String hel ...

  6. Java入门:Java中获取键盘输入值的三种方法

    Java程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值的现成函数!Java没有提供这样的函数也不代 ...

  7. JAVA中创建线程池的五种方法及比较

    之前写过JAVA中创建线程的三种方法及比较.这次来说说线程池. JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用.另一类是通过Thr ...

  8. JAVA中获得一个月最大天数的方法(备忘)

    Calendar 类是一个抽象类,为日历字段之间的转换提供了一些方法.其中有一个重要方法 getActualMaximum ,该方法用于返回指定日历字段实际的最大值. 利用这个方法(Calendar. ...

  9. Java中的Object类的几个方法

    Object类被称为上帝类,也被称为祖宗类.在定义Java类时,如果没有指定父类,那么默认都会去继承Object类.配合Java的向上类型转换,借助Object类就可以完成很多工作了. 在Object ...

随机推荐

  1. 李航统计学习方法(第二版)(六):k 近邻算法实现(kd树(kd tree)方法)

    1. kd树简介 构造kd树的方法如下:构造根结点,使根结点对应于k维空间中包含所有实例点的超矩形区域;通过下面的递归方法,不断地对k维空间进行切分,生成子结点.在超矩形区域(结点)上选择一个坐标轴和 ...

  2. 微信小程序开发部署

    一.开发准备 1,想要开发微信小程序,必须要有一个AppId,如果没有可以去注册一个.   https://mp.weixin.qq.com/进入注册页面,点击上方注册.   2,点击选择“小程序”出 ...

  3. dva + umi 学习笔记

    首先,这里的 dva + umi 不是说学习dva和umi,而是基于 dva + umi 的react前端开发脚手架,这是我的目标. 一开始,我在dva文档的例子里看到了 dva + umi 的例子. ...

  4. cmd : 代理设置/检验代理设置成功

    设置代理很简单,一句话的事儿. set HTTP_PROXY=http://user:password@proxy.domain.com:port 比如说,我用ssr,默认地址是127.0.0.1:1 ...

  5. p41_数据报与虚电路

    一.定义 数据报方式为网络层提供无连接服务. 无连接服务:不事先为分组的传输确定传输路径,每个分组独立确定传输路径,不同分组传输路径可能不同. 虚电路方式为网络层提供连接服务 连接服务:首先为分组的传 ...

  6. vscode用MinGW和Clang配置C++环境

    vscode是个不错的编辑器,简洁轻量,就是一开始的时候需要对环境进行配置,开个贴记录一下怎么用MingGW64+clang来配置. 下载地址 LLVM Download Page Pre-Built ...

  7. 动手实现一个简单的 rpc 框架到入门 grpc (下)

    之前手动实现了一次简陋的 rpc 调用,为了简单使用了 json 编码信息,其实这是非常不可靠的,go 中 json 解析会有一些问题,比如整数会变成浮点数,而且 json 字符串比较占空间. gRP ...

  8. 在ASP.NET中,<%= %>和<%# %>有什么区别

    asp.net中<%#%>出现在repeater gridview等控件中.用以绑定控件的datasource asp.net中<%%>的意思是 上运行c#或者vb代码,比如: ...

  9. git的核心命令使用和底层原理解析

    文章目录: GIT体系概述 GIT 核心命令使用 GIT 底层原理 一.GIT体系概述 GIT 与 svn 主要区别: 存储方式不一样 使用方式不一样 管理模式不一样 1.存储方式区别 GIT把内容按 ...

  10. jsp课堂笔记1

    http协议:规范浏览器和服务器交互或通信的规则 https:基于http实现,比http更加安全,提供了身份验证和通信内容加密  服务器:1.配置比较高的电脑  2.他就是一个应用 http1.0: ...