代理模式
**代理模式的定义:**代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
代理模式分为静态代理和动态代理
静态代理
静态代理的步骤
第一步:编写一个代理接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBri5aYW-1606474534791)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201125201656262.png)]
第二步:编写实现这个接口的实现类, 这个实现类必须包含被代理类对象
package proxy1;
/**
* 静态代理模式: 代理类编写出来
* 如果对目标类的每一个目标方法进行相同的增强的代码
* 需要在代理类中每一个方法内写相同的代码,
* 缺点: 增强代码重复写
* 代理类
* 打折
* @author THINK
*
*/
public class SellProxy1 implements ISellabel {
// 核心的代码 代理类中必须包含一个被代理的对象
private ISellabel proxy; //被代理对象
public SellProxy1(ISellabel proxy) {
super();
this.proxy = proxy;
}
@Override
public void sellKongdiao() {
//执行目标类的目标方法: MeiDe类sellKongdiao()
proxy.sellKongdiao();
//super.sellKongdiao();
System.out.println("打八折"); // 增强的代码
}
@Override
public void sellBingxiang() {
proxy.sellBingxiang();
System.out.println("打八折");
}
}
第三步:编写被代理类对象,也要实现这个接口
package proxy1;
public class Geli implements ISellabel {
@Override
public void sellKongdiao() {
System.out.println("格力空调2880");
}
@Override
public void sellBingxiang() {
System.out.println("格力冰箱1280");
}
}
package proxy1;
/**
* 美的公司
* @author THINK
* 被代理类, 目标类
*/
public class MeiDe implements ISellabel{
/**
* 卖空调
* 目标方法
*/
@Override
public void sellKongdiao(){
System.out.println("美的空调2980元");
}
/**
* 卖冰箱
* 目标方法
*/
@Override
public void sellBingxiang(){
System.out.println("美的冰箱980元");
}
}
编写测试类
package proxy1;
public class Test {
public static void main(String[] args) {
//美的做活动, 打八折
MeiDe meiDe = new MeiDe();
//创建一个代理类对象
SellProxy1 sp = new SellProxy1(meiDe);
sp.sellKongdiao();
//美的做活动, 打八折
Geli geli = new Geli();
//创建一个代理类对象
SellProxy1 sp1 = new SellProxy1(geli);
sp1.sellKongdiao();
}
}
这种 代理方式存在极为明显的缺点:
1、增强的代码都一样,同样的语句需要写多次
2、代理累的每个方法结构相似,看上去也像是大量重复的代码
动态代理
使用动态代理的步骤,代理类不需要我们自己创建,实现动态代理的技术通过jdk自带的或者第三方的jar包,cglib
使用jdk自带的Proxy类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0bwwc8vN-1606474534794)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201126184759970.png)]
package proxy2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 执行器处理器
* 拦截器(过滤器), 拦截的 代理类的调用方法的时候拦截
* @author THINK
*
*/
public class MyInvocationHandler implements InvocationHandler {
private ISellabel target; //目标类, 被代理类对象
public MyInvocationHandler(ISellabel target) {
super();
this.target = target;
}
/**
* 当代理类调用方法的时候, 先要执行invoke() 方法
* 每次调用方法
* proxy: 代理类对象
* method: 目标方法对象, 调用哪个方法的对象
* args: 参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//等同于 proxy.sellKongdiao(); 执行被代理类的目标方法
//如果目标方法是void, invoke() 返回 null
// 反射: method.invoke(obj, 参数) obj.方法名(args)
Object rs = method.invoke(target, args);
//增强代码
System.out.println("打八折");
return rs;
}
}
接口类和被代理类一样。
这种模式,在mybatis里会用到,Mybatis的getMapper就用到了这种方法。
obj.方法名(args)
Object rs = method.invoke(target, args);
//增强代码
System.out.println(“打八折”);
return rs;
}
}
接口类和被代理类一样。
这种模式,在mybatis里会用到,Mybatis的getMapper就用到了这种方法。