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();
    }
}

  • 运行效果
    java装饰者模式解析&&动态代理解决装饰者模式的缺点
    可以看到,我们的 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中定义了多少方法,我们只需要把需要我们自定义的功能或方法在InvocationHandlerinvoke方法中实现即可

代码运行效果

java装饰者模式解析&&动态代理解决装饰者模式的缺点