当前位置: 首页 > 科技观察

代理模式,拿走!!!

时间:2023-03-13 02:25:23 科技观察

本文转载自微信公众号《小浪密码问答》,作者西门浪。转载本文请联系小浪码答公众号。代理模式就是为一个对象提供一个代理对象,由代理对象控制对原对象的引用。通俗地说,代理模式就是我们所知道的中介。以我们熟悉的商品代购为例:如果我们需要购买一件物品,我们可以直接去工厂购买;或者我们可以找代购。如果我们直接去工厂购买的话,需要在购买之前对自己要购买的物品做一些调查,然后直接去工厂提货,这样一切都需要自己来完成。如果我们通过代购购买,我们只需要告诉代购我们需要什么,代购会帮我们处理剩下的事情(研究、采购),最后给我们需要的相应物品。因此,代理模式的目标如下:(1)通过引用代理对象间接访问目标对象,避免直接访问目标对象给系统带来不必要的复杂性。(2)通过代理对象增强原有业务。一般情况下,根据代理的创建周期,一般可以分为两种:静态代理静态代理是程序员或特定工具自动生成源代码,然后进行编译。在程序运行之前,代理类编译生成的.class文件已经存在。动态代理是在程序运行时通过反射机制动态创建的。1.静态代理模式静态代理中代理类和委托类的关系是在运行前确定的,如图:静态代理特别注意几个概念:抽象对象抽象对象声明了公共接口真实对象和代理对象。真实对象代理对象所代表的真实对象就是最终被引用的对象。代理对象包含真实对象,然后操作真实对象,相当于访问者和真实对象之间的直接中介。接下来我们举个例子:(1)创建一个服务类接口publicinterfaceBuyCar{voidbuycar();}(2)服务实现类publicclassBuyCarImplimplementsBuyCar{publicvoidbuycar(){System.out.println("BuyanAudi");}}(3)创建一个代理类publicclassBuyCarProxyimplementsBuyCar{privateBuyCarbuyCar;publicBuyCarProxy(BuyCarbuyCar){this.buyCar=buyCar;}publicvoidbuycar(){System.out.println("买车前的调查...");buyCar.buycar();System.out.println("买车后的保养...");}}(4)写一个测试类buyCarProxy.buycar();}}优点:静态代理可以通过代理对象扩展目标对象,而不需要修改目标对象。代理类可以让客户端不需要知道具体的实现类是什么,怎么做。客户端只需要知道代理即可(解耦)缺点:代理类和具体的实现类实现相同的接口,代理类通过实现类实现相同的方法。这会产生大量代码重复。如果接口增加了一个方法,除了所有的实现类都需要实现这个方法外,所有的代理类也需要实现这个方法。增加了代码维护的复杂性。代理对象只服务于一种类型的对象,如果它想服务于多种类型的对象的话。需要对每个对象进行代理,程序规模稍大时静态代理无法胜任。2.动态代理模式2.1JDK自带的其实单个代理是不存在的,一个代理可以同时承担多个角色。你可以买车或买房子。在动态代理中,我们不再需要手动创建代理类,我们只需要一个动态处理器,真正的代理对象是由JDK运行时动态创建的。(1)创建服务类接口//买车接口publicinterfaceBuyCar{voidbuycar();}//买房接口publicinterfaceBuyHouse{voidbuyHouse();}(2)服务实现类//买车接口实现类publicclassBuyCarImplimplementsBuyCar{publicvoidbuycar(){System.out.println("买奥迪");}}//买房接口实现类publicclassBuyHouseImplimplementsBuyHouse{publicvoidbuyHouse(){System.out.println("买大别墅");}}(3)动态Proxy类//通过实现InvocationHandler接口创建自己的调用处理器;publicclassProxyHandlerimplementsInvocationHandler{privateObjectobject;//通过构造函数创建动态代理类实例,构造时将调用处理程序对象作为参数传入。publicProxyHandler(Objectobject){this.object=object;}publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("Beforeinvoke"+method.getName());method.invoke(object,args);System.out.println("Afterinvoke"+method.getName());returnnull;}}(4)测试类InvocationHandlerhandler=newProxyHandler(buyHouse);InvocationHandlerhandler1=newProxyHandler(buyCar);/***通过指定ClassLoader对象和Proxy类的一组接口创建动态代理类;*/BuyHouseproxyHouse=(BuyHouse)Proxy.newProxyInstance(buyHouse.getClass().getClassLoader(),buyHouse.getClass().getInterfaces(),handler);BuyCarproxyCar=(BuyCar)Proxy.newProxyInstance(buyCar.getClass().getClassLoader(),buyCar.getClass().getInterfaces(),处理程序1);proxyHouse.buyHouse();proxyCar.buycar();}}请注意,Proxy.newProxyInstance()方法接受三个参数:publicstaticObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)ClassLoader加载器:指定当前目标对象使用类加载器,获取加载器的方法是固定的Class[]interfaces:指定目标对象实现的接口类型,使用通用方法确认类型。InvocationHandlerh:指定动态处理器,当目标对象的方法执行时,会触发事件处理器的方法。2.2CGLIBCGLIB比JDK动态代理更强大。JDK动态代理虽然简单易用,但是它有一个致命的缺陷,就是只能代理接口。如果被代理的类是一个没有接口的普通类,那么就不能使用Java动态代理。在使用cglib之前,需要先添加依赖。cglibcglib3.2.12(1)目标类DaopublicclassDao{publicvoidupdate(){System.out.println("PeopleDao.update()");}}Dao1publicclassDao1{publicvoidselect(){System.out.println("PeopleDao.select");}}(2)代理类publicclassDaoProxyimplementsMethodInterceptor{publicObjectintercept(Objectobject,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{System.out.println("BeforMetodInvoke");methodProxy.invokeSuper(object,objects);System.out.println("AfterMethodInvoke");returnnull;}}参数说明:Object代表要增强的对象Method代表拦截方法的Object[]数组代表参数列表,其封装类型中需要传入基本数据类型,如int-->Integer,long-Long,double-->DoubleMethodProxy代表代理为方法,invokeSuper方法表示方法的代理是Proxy对象方法call(3)测试publicclassCglibProxyTest{publicstaticvoidmain(String[]args){DaoProxydaoProxy=newDaoProxy();Enhancerenhancer=newEnhancer();Enhancerenhancer1=newEnhancer();//设置要继承的父类enhancer.setSuperclass(Dao.class);enhancer1.setSuperclass(Dao1.class);//设置回调方法enhancer.setCallback(daoProxy);enhancer1.setCallback(daoProxy);//创建动态代理类Daodao=(Dao)enhancer.create();Dao1dao1=(Dao1)enhancer1.create();dao.update();System.out.println(".........................................");dao1.select();}}

最新推荐
猜你喜欢