反射原理及动态代理模式(二)

一、什么是代理模式

前面说了那么多原理,那么反射到底什么时候用呢?研究过设计模式的朋友应该听过代理模式,代理模式就是给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用(经常找人代购各种化妆品的小姐姐应该一听就明白了,如果还有不懂的男同胞,那只能祝你金牌单身汪快乐!哈哈)。代理模式又分为静态代理模式和动态代理模式。而动态代理模式就需要用到我们的反射。

二静态代理和动态代理的区别

这里先简单说一下这两种代理模式的区别:

1、静态代理模式:所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

2、动态代理模式:动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。

那么为什么要用到代理模式呢?专业点的解释就是:(1)、通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性(毕竟目标对象是个会见不得人会害羞的漂亮小姐姐,所以和她对话只能通过中间人来完成)。(2)、通过代理对象对原有的业务进行增强(嗯,这一句理解起来可能有点难度)。

这里我们拿代购来举例,其实不管是小姐姐直接去商家哪里购买化妆品,还是从代理哪里买。商家和代理都是对外提供一个卖的动作。而这个卖的动作我们就可以定义为一个接口。但是正真实现这个卖接口,生产出化妆品的是商家。代理只是获取了商家的代理权(持有真实对象从而操作真实对象),毕竟要考虑到国外用户的需要嘛,让国外用户直接上门购买,路途遥远不现实啊,所以需要代理这样的中介出现。于是对于国外用户来说,购买入口就只有代理了。

 下面通过撸代码,带大家看看什么是代理模式,以及静态代理和动态代理的具体区别。

     /**
         *    静态代理模式
         */
        //代理品牌A
        ACosmeticFactory factoryA = new ACosmeticFactory();
        CosmeticProxy proxyA = new CosmeticProxy(factoryA);//代理A
        Lipstick lipsticka = (Lipstick) proxyA.SellCosmetic("com.demo.singlecode.reflectdemo.proxy.Lipstick");
        lipsticka.onBecomeBeautiful();
        Mask maska = (Mask) proxyA.SellCosmetic("com.demo.singlecode.reflectdemo.proxy.Mask");
        maska.onBecomeBeautiful();

        //代理品牌B
        BCosmeticFactory factoryB = new BCosmeticFactory();
        CosmeticProxy proxyB = new CosmeticProxy(factoryB);//代理B
        Lipstick lipstickb = (Lipstick) proxyB.SellCosmetic("com.demo.singlecode.reflectdemo.proxy.Lipstick");
        lipstickb.onBecomeBeautiful();
        Mask maskb = (Mask) proxyB.SellCosmetic("com.demo.singlecode.reflectdemo.proxy.Mask");
        maskb.onBecomeBeautiful();

 下面是静态代理的运行结果:

 看完上面的代码,有的同学会问,现在市场上化妆品品牌那么,但是这个代理就只代理品牌A的化妆品,满足不了需求啊,如果某一天又出来一箩筐好的品牌,小姐姐们又想要,那这个这时候小姐姐们要么换代理,要么这个代理就得修改代码增加接口来满足需求啦。(是哇,养小姐姐好难哇,化妆品牌子辣么多!)这就导致每多出来一个新品牌就得换代理,或者让代理修改代理接口(这也就是我们常说得扩展性差问题)。那么怎样做到一个代理不需要修改接口,就能够代理所有品牌的化妆品呢?答案当然是动态代理模式。

那么有一天我发现这个现象后,突发奇想,开了一个代购公司。然后以公司得名义打通获取所有品牌商的代购权。这个时候不管哪个小姐姐来想要什么品牌的化妆品我们都能够满足(于是我成了所有男同胞仇恨的对象!哈哈)。那么代码里如何实现这一设想呢?

      /**
         * 动态代理模式
         */
        ProxyCompany company = new ProxyCompany();//代理公司,这里我们只显示的创建了一个对象
        FactoryInterface proxyA = (FactoryInterface) company.getProxyInstance(ACosmeticFactory.class);//输入需要的品牌,返回负责这个品牌的代理人员
        Mask maskA = (Mask) proxyA.SellCosmetic("com.demo.singlecode.reflectdemo.proxy.Mask");//输入化妆品名称,返回化妆品
        maskA.onBecomeBeautiful();

        FactoryInterface proxyB = (FactoryInterface) company.getProxyInstance(BCosmeticFactory.class);
        Mask maskB = (Mask) proxyB.SellCosmetic("com.demo.singlecode.reflectdemo.proxy.Mask");
        maskB.onBecomeBeautiful();

 动态代理运行结果如下:

 对比一下静态代理的代码和动态代理代码我们可以发现

(1)、相同的事情,动态代理的代码量更少。

(2)、动态代理更加灵活,首先不会因为出现新品牌就需要去修改代码,或重新new新的代理对象,比静态代理拥有更好的扩展性。

(3)、动态代理和被代理对象更加解耦,不会因为被代理接口的变更而要修改代理类的代码。比如被代理的品牌新出了一款化妆品的时候,并不需要修改动态代理的代码,依然能够完成代理工作。

有人会说你,这代理公司类里面一定写的很复杂才能完成这么多品牌的代理。那么见证奇迹的时候到了。

package com.demo.singlecode.reflectdemo.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 创建时间:2019/5/25
 * 创建人:singleCode
 * 功能描述:代购公司
 **/
public class ProxyCompany implements InvocationHandler {
    private Object factory;//持有真实对象

    public Object getProxyInstance(Class<?> factoryClass){
        try {
            factory = factoryClass.newInstance();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return Proxy.newProxyInstance(factory.getClass().getClassLoader(),factory.getClass().getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(factory,args);//通过反射调用被代理对象的方法
        return result;
    }
}

需要代码的小伙伴们可以关顾本人github

发布了29 篇原创文章 · 获赞 3 · 访问量 905

猜你喜欢

转载自blog.csdn.net/LVEfrist/article/details/90546178