什么是代理模式?
那么什么是代理呢?
日常生活中的代理
这个中介学校就是代理,就是第三方在学校和家长之间赚取费用
而且,现在这种模式,会比平时家长直接找学校多收取了中介费
这笔中介费,就是代理的增强
那么我们为什么需要找中介?为什么需要找代理呢?
日常生活需要中介
开发中需要代理
此时b就是代理
生活中开发程序的代理情况
举例
代理模式的作用
我们之前上外国大学的例子,中介代理收取的中介费,就是增强
实现代理的方式——静态代理和动态代理
静态代理
自己实现静态代理
定义一个接口表示规范
现在市场里有金士顿这个牌子,所以要遵守市场规范
这是目标类,表示u盘的厂家,因为要在这个市场,所以需要遵守市场规范(要实现接口)
但是此时厂家不和用户买卖(因为用户买的太少了)
现在当作大家都只买一个u盘,一个u盘85元
但是用户确实是需要u盘,厂家不直销,应该找一些之间代理的商铺去购买,但是商铺也要遵守市场规范
package com.LALALA.shangjia; import com.LALALA.factory.UsbKingFactory; import com.LALALA.service.UsbShell; //代理类,现在我们的淘宝要做金士顿的代理,但是也要遵守市场规范 public class TaoBao implements UsbShell { //首先告诉大家自己是誰的代理 private UsbKingFactory factory = new UsbKingFactory(); //这里真正的向用户卖u盘,但是自己没法造,就要联系厂家 @Override public float shell(int amount) { float price = factory.shell(amount);//联系厂家,获得厂家的售价 //商家做代理肯定需要加价钱 price = price + 25;//商家每个u盘赚取25元 //返回给用户自己卖多少钱 return price; } }
最后就是用户向淘宝商家购买u盘
package com.LALALA; import com.LALALA.shangjia.TaoBao; public class ShopMain { public static void main(String[] args) { //要先找到一个淘宝商家 TaoBao taoBao = new TaoBao(); //调用淘宝的方法进行购买 float price = taoBao.shell(1); System.out.println("by taobao buy u price::::"+price); } }
此时输出
完成了一套静态代理的流程
这就实现了淘宝对用户的访问控制(不让你去品牌工厂购买)
这就实现了淘宝对用户的方法增强(比起去工厂买,多收了25块)
注意:实现目标类的方法之后,都属于增强的功能
我们在目标类中写一个验证
譬如现在淘宝卖给你u盘后,给了一张优惠卷也属于是功能增强
现在的测试:
淘宝(代理类)的加钱和返回优惠卷都是方法的增强,但是u盘制造(目标类)还是厂家完成的
静态代理的缺点
我们不仅可以淘宝代理金士顿u盘,微商也可以
微商只挣1块钱
用户在微商这边购买
但是制造u盘的厂家也可能不止一个
同样也会有代理
缺点一:增加了一个厂家,代理要成倍的增长
如果市场有了一个新规范
缺点二:此时我们的所有代理和厂家都要进行更改
如何解决这些问题呢?
可以使用动态代理
动态代理
动态代理的定义
什么是动态代理?
在我们之前写的静态代理的 代理类中,我们需要每个代理类都要写死一个自己代理的是哪个目标类,而我们现在的动态代理可以动态的指定要给哪个目标类创建代理,在程序执行的时候才会创建代理类的对象
动态代理的分类(分为有接口的情况和没有接口的情况)
复习Method类
定义一个简单的接口和实现类,目标是想说hello加名字
此时会成功输出
但是我们想利用反射机制执行sayhello方法
再使用method.invoke就可以了
但是这个方法中有两个参数,应该填写什么呢?
所以第一个参数要指出要执行哪个对象的方法(我们上面new过了接口),第二个参数填写参数值(直接写名字,例如张三李四),最后返回的也是一个对象
此时我们的method已经找到了要执行哪个方法,所以只要填写对象和参数就可以了
如果这个接口有其他的实现类也想这样子执行可不可以呢?
可以,只需要再new一个实现类并且invoke就可以了
此时通过invoke就可以执行任意对象实现类中的sayhello方法了
实现动态代理的三个类
这三个类都是干什么的?
InvocationHandler
我们需要把在代理类中增加的语句写在这个接口的方法里
其中method就是我们上面复习的,找到了某个对象的某个方法,args就是这个方法里需要的参数
但是这些都是JDK会帮我们做的,不用我们进行赋值
用起来还是比较简单的
Method
factoy就是service2(在准备反射的时候被new好了)
amount就是李四(填写方法执行的参数)
.sell就是method.(在之前使用了.getMethod获取了我们指定的方法名称,存在method这个对象里了)
主要是实现InvocationHandler里的调用目标方法,要写在InvocationHandler里面
Proxy
这玩意就是我们之前用户去找淘宝店的功能
最后返回的对象当成之前的淘宝店使用就好了,但是现在的这东西是个对象类型,所以在使用时还需要把他转换为我们需要的接口类型
动态代理的实现
步骤
第一步
第二步
第三步
package com.LALALA.handler; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //动态代理必须实现InvocationHandler的接口,完成代理类要做的功能(调用目标方法,功能增强) public class MyShellHandler implements InvocationHandler { private Object target; //传入的是谁,就赋值给谁,方便method使用 public MyShellHandler(Object target) { //给目标对象赋值 this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //先把原本静态的代理类内代码复制过来看看 //float price = factory.shell(amount);//联系厂家,获得厂家的售价 //定义一个res对象接收method.invoke的执行结果 Object res = null; //现在我们知道要执行哪个方法(method),也知道执行的参数填写(args),那么对哪个对象执行呢? //我们现在是动态代理,需要从外面传入,传入哪个就执行哪个,就很动态 res = method.invoke(target,args); //商家做代理肯定需要加价钱 //price = price + 25;//商家每个u盘赚取25元 //判断并且增强 if (res!=null){ Float price = (Float) res; price = price + 25; res = price; } System.out.println("give you money 10yuan"); //返回给用户自己卖多少钱 //现在返回res就可以了 return res; } }
第四步
创建代理对象,但是代理对象里面需要参数,所以要创建目标对象,和handler对象
准备工作好了,现在创建代理对象并且填入参数
现在Proxy是一个对象,要强制转换为我们想用的接口进行使用
测试成功
动态代理执行的流程图
所以动态代理可以干什么?
现在假设我们没办法动用GongNeng类的源文件,但是我感觉它的pring方法不好,应该返回的是结果的2倍,学习完动态代理就可以完成了
测试成功