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