java装饰者模式解析&&动态代理解决装饰者模式的缺点
需求描述: 假如谷歌公司根据sun公司规定的接口实现了一套自己的智能汽车系统。 包括 汽车启动,汽车运行,汽车停止。 作为 第三方公司的我们,我们想
基于谷歌公司的汽车系统做二次开发,加入 天气检测功能和路况检测功能。
装饰者模式描述
- 某个语言(以java为例)定义了一套功能接口(例如: 智能汽车接口,ICar)
- 某公司(以谷歌为例)实现了这套接口,做了自己的实现(例如:GoogleCar )。(拥有
启动、运行、停止
功能) - 其他公司(例如我们)想基于 谷歌的这套实现做二次开发(想加入
天气检测、路况检测
功能) - 那我们定义我们自己的一个类(MyCar), 并实现 ICar 接口,以及其中所有的方法
- 并在 MyCar 中定义一个 构造函数 接受一个 ICar 接口对象(在使用时吧 GoogleCar传进来)
- 在MyCar类中需要我们自定义的功能时,我们加入我们自己的代码,不需要我们自定义的功能时,我们直接调用传入的GoogleCar 的方法。
示例demo
- ICar 接口
public interface ICar {
public void start();
public void run();
public void stop();
}
- GoogleCar实现类
public class GoogleCar implements ICar {
@Override
public void start() {
System.out.println("谷歌汽车启动了");
}
@Override
public void run() {
System.out.println("谷歌汽车正在运行");
}
@Override
public void stop() {
System.out.println("谷歌汽车停止");
}
}
- 我们基于 GoogleCar(或者其他实现ICar的类) 的实现类 MyCar
public class MyCar implements ICar{
ICar iCar = null;
public MyCar(ICar iCar) {
this.iCar = iCar;
}
public ICar getInstance(){
return iCar;
}
@Override
public void start() {
System.out.println("检查天气是否良好");
System.out.println("检查路况是否拥堵");
iCar.start();
}
@Override
public void run() {
iCar.run();
}
@Override
public void stop() {
iCar.stop();
}
}
- 调用我们自己的功能 Test类
public class Test {
public static void main(String[] args) {
ICar car = new MyCar(new GoogleCar());
car.start();
car.run();
car.stop();
}
}
- 运行效果
可以看到,我们的 MyCar不但 有 我们自己的天气检测、路况检测
,还有 google公司的汽车启动,汽车运行,汽车停止
的功能。
装饰者模式存在问题
问题描述: 假如sun公司在 定义 ICar时定义了 200个接口,那我们去实现ICar的话就需要自己实现200个方法,其中需要我们自定义或者开发的可能就一两个。
解决方案 – 使用动态代理
- 我们把以上我们自己实现类MyCar删掉
示例代码
- ICar 接口类(start方法增加了参数和返回值)
public interface ICar {
public String start(int a,int b);
public void run();
public void stop();
}
- 谷歌实现类 GoogleCar
public class GoogleCar implements ICar {
@Override
public String start(int a, int b) {
System.out.println("谷歌汽车启动了" + a + " -- " + b + "");
return "谷歌汽车启动了" + a + " -- " + b + "";
}
@Override
public void run() {
System.out.println("谷歌汽车正在运行");
}
@Override
public void stop() {
System.out.println("谷歌汽车停止");
}
}
- 使用动态代理 的测试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
//1param: 固定值: 告诉虚拟机用哪个字节码加载器加载内存中创建出的字节码文件
//2param: 告诉虚拟机内存中正在被创建的字节码文件中应该有哪些方法
//3param: 告诉虚拟机正在被创建的字节码上的各个方法如何处理
ICar car=(ICar)Proxy.newProxyInstance(Test.class.getClassLoader(), GoogleCar.class.getInterfaces(),new InvocationHandler() {
//method:代表正在执行的方法
//args:代表正在执行的方法中的参数
//Object:代表方法执行完毕之后的返回值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//经过测试得知:method代表当前正在执行的每个方法
//System.out.println(method.getName());
//执行当前的方法
//method.invoke(new GoogleCar(), args);
//代表每个方法执行完毕之后返回对象
Object obj=null;
if(method.getName().equalsIgnoreCase("start")){
System.out.println("检查天气是否良好");
System.out.println("检查路况是否拥堵");
obj=method.invoke(new GoogleCar(), args);
}else{
obj=method.invoke(new GoogleCar(), args);
}
return obj;
}
});
String cc=car.start(1,4);
car.run();
car.stop();
System.out.println(cc);
}
}
这样,不管ICar中定义了多少方法,我们只需要把需要我们自定义的功能或方法在InvocationHandler
的invoke
方法中实现即可