装饰者模式: 静态代理
1.壳子(装饰者类)必须跟 原本对象 实现同一个接口,保证调用方法 跟以前没有区别 上层不用改
2.装饰者类 必须持有原本对象的引用 (提供构造方法,传入原本实现类),装饰者不是真正逻辑,只是为了给原方法额外增加一些通用型逻辑(例如添加sql事务)
3.不需要增强的就完全直接调用原本实现类
4.需要增强得随便加逻辑
优点:可以无侵入(不修改源代码)增强逻辑
缺点: 需要给每一个需要增强的类手动套壳,
需要实现接口中的所有抽象方法
导致类结构爆炸
一句话概述:不改变需要装饰(增强)的类的代码.新写一个包装类,给需要装饰的类的方法添加上新的业务代码,不需要装饰的方法则返回原方法.
动态代理:
实现方式:在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。
好处:不需要导入别人的包
坏处:要被增强对象必须有个爹(接口)
java.lang.reflect.Proxy 类
Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)
返回一个已经被增强过的对象
loader:获取类的加载器(需要使用自己的类来获取。不是自己的加载器无法使用:例如使用String类获取的加载器就无法使用)
interfaces: 获取原本对象的接口数组(接口可以多实现,所以接口可能会有多个)
InvocationHandler:执行处理类
//接口InvocationHandler中实际干活的方法
Object invoke(Object proxy, Method method, Object[] args)
proxy:即将返回的被增强对象,仅在链式编程(下方的didi方法)时使用,其他情况勿用
method:在调用 需要增强对象(ferrari)的方法(例如run)的时候的方法(method)本身
args:在调用增强对象(ferrari)的方法(例如run)的时候的方法本身传入的实参
一句话概述:不改变需要装饰(增强)的类的原代码.使用jdk原生的proxy类的方法newProxyInstance来创建一个实现类,完成对原方法的逻辑增强, 多态的形式将实现类返回给一个接口对象
一个简单的例子,辅助理解
接口Car
package com.xxx.proxy.wrapper;
public interface Car {
void run();
void stop();
int oilTank();
void driver(String driverName);
Car didi();
}
实现类Ferrari
package com.xxx.proxy.wrapper;
public class Ferrari implements Car {
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println("法拉利完成百公里加速");
} catch (Exception e) {
}
}
@Override
public void stop() {
System.out.println("法拉利刹车了");
}
@Override
public int oilTank() {
return 100;
}
@Override
public void driver(String driverName) {
System.out.println(driverName+"正在驾驶法拉利");
}
@Override
public Car didi() {
System.out.println("法拉利正在滴滴滴");
return this;
}
}
静态代理增强Ferrari
package com.xxx.proxy.wrapper;
/**
* 装饰者模式: 静态代理
*
* 1.壳子(装饰者类)必须跟 原本对象 实现同一个接口,保证调用方法 跟以前没有区别 上层不用改
* 2.装饰者类 必须持有原本对象的引用 (提供构造方法,传入原本实现类),装饰者不是真正逻辑,只是为了给原方法额外增加一些通用型逻辑(例如添加sql事务)
* 3.不需要增强的就完全直接调用原本实现类
* 4.需要增强得随便加逻辑
*
* 优点:可以无侵入(不修改源代码)增强逻辑
*
* 缺点: 需要给每一个需要增强的类手动套壳,
* 需要实现接口中的所有抽象方法
* 导致类结构爆炸
*/
public class FerrariWrapper implements Car {
private Car ferrari;
public FerrariWrapper(Car ferrari) {
super();
this.ferrari = ferrari;
}
/**
* 给ferrari的run方法增加一个计时,不改变原代码的情况下,给方法新增了逻辑
*/
@Override
public void run() {
long start = System.currentTimeMillis();
ferrari.run();
long end = System.currentTimeMillis();
System.out.println("百公里加速用时"+(end-start));
}
@Override
public void stop() {
ferrari.stop();
}
@Override
public int oilTank() {
return ferrari.oilTank();
}
@Override
public void driver(String driverName) {
ferrari.driver(driverName);
}
@Override
public Car didi() {
return this;
}
}
动态代理增强Ferrari
package com.xxx.proxy.wrapper;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CarTest {
public static void main(String[] args) {
//创建一个实现类对象ferrari
final Ferrari ferrari = new Ferrari();
/**
* 套壳 使用java.lang.reflect.Proxy的方法newProxyInstance
* loader:类加载器 传入一个负责把被增强对象所对应的类加载到内存的类加载 传入原本对象的类加载器 或者接口的类加载器
* interfaces: 传入原本对象的接口 数组
* InvocationHandler:执行处理接口
*/
Car proxyFerrari = (Car) Proxy.newProxyInstance(
//获取类的加载器(需要使用自己的类来获取,不是自己的加载器无法使用:例如使用String类获取的加载器就无法使用)
CarTest.class.getClassLoader(),
//获取原本对象的接口数组(接口可以多实现,所以接口可能会有多个)
new Class[]{Car.class},
//InvocationHandler接口,执行处理类
new InvocationHandler() {
/**
* 底层会生成一个实现类
* @param proxy 即将返回的被增强对象,仅在链式编程(下方的didi方法)时使用,其他情况勿用
* @param method 在调用 需要增强对象(ferrari)的方法(例如run)的时候的方法(method)本身
* @param args 在调用增强对象(ferrari)的方法(例如run)的时候的方法本身传入的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("run".equals(method.getName())) {
//原方法无形参,无返回值,使用proxy增加一个逻辑(运行耗时)
long start = System.currentTimeMillis();
method.invoke(ferrari, args);
long end = System.currentTimeMillis();
System.out.println("百公里加速耗时:" + (end - start));
} else if ("oilTank".equals(method.getName())) {
//原方法oilTank有int类型的返回值,使用proxy修改原返回值
int oilTank = (int) method.invoke(ferrari, args);
return oilTank + 50;
} else if ("driver".equals(method.getName())) {
//原方法需要形参driverName,使用proxy修改传入的driverName
args[0] = "老司机" + args[0];
method.invoke(ferrari, args);
} else if ("didi".equals(method.getName())) {
//为了链式变成,要求方法的返回值是自己
System.out.println("增强对象还在运行...");
Object invoke = method.invoke(ferrari, args);
//返回incoke,链式编程从第二次调用开始就是走原方法的逻辑
//return invoke;
//返回proxy,链式编程继续走proxy逻辑
return proxy;
} else {
//不需要修改原方法,直接运行原方法
method.invoke(ferrari, args);
}
return null;
}
}
);
System.out.println("================华丽的分割线================");
proxyFerrari.run();
System.out.println("================华丽的分割线================");
System.out.println(proxyFerrari.oilTank());
System.out.println("================华丽的分割线================");
proxyFerrari.driver("拓海");
System.out.println("================华丽的分割线================");
proxyFerrari.didi().didi();
}
}