代理模式
有天狗蛋在网上买了件黑丝,快递到了狗蛋忙着当王者荣耀,没空去拿于是狗蛋叫了个跑腿帮他拿快递,哎....这有没有代理的味道呢?狗蛋还让跑腿帮他带包烟 666 啊。
其实生活中有很多代理模式的影子,代理模式起到一个中介的作用,例如我们要买房子怎么办呢?当然是找中介了,那这个中介就是代理对象啦。
代理模式的结构:
- 抽象主题:声明真实主题和代理要实现的方法
- 真实主题:实现抽象主题 (目标对象,其实就是要被代理的类啦)
- 代理类:实现抽象主题 (代理对象)
我们分析一下,狗蛋和跑腿要做的事情是不是同一件事呢?当然了都是拿快递嘛...中介和卖房子的客户他们要做事情都是卖房子啊。既然大家一样的目标,所以真实主题和代理类都要实现抽象主题接口啦。
在这个例子中:抽象主题角色是Subject接口,真实主题角色是GetPackage类,代理类角色是Proxy类,这里边代理类角色充当了跑腿小哥,狗蛋是调用者,如果狗蛋自己调用目标对象(真实主题类)的方法,相当于自己去拿快递,如果调用代理对象(代理类)的方法就是叫了跑腿啦。
***********************静态代理模式实现 *******************
代理模式类图:
抽象主题代码
/**
* 抽象主题类:这个接口是目标对象(真实主题类)和 代理对象(代理类)都要共同实现的接口
*/
public interface Subject {
// 拿快递的方法
void getExpress();
}
真实主题代码
/**
* 具体主题:(目标对象)
*/
public class GetPackage implements Subject{
// 拿快递的方法
@Override
public void getExpress() {
System.out.println("拿了快递...");
}
}
代理类代码
/**
* 代理类
*/
public class Proxy implements Subject {
// 聚合目标对象
private GetPackage getPackage = new GetPackage();
// 拿快递的方法
@Override
public void getExpress() {
// 拿快递
getPackage.getExpress();
// 帮客户买烟
System.out.println("买了一包电杆(中华的别名)...");
}
}
测试代码
public class Test {
public static void main(String[] args) {
// 创建代理对象
Proxy proxy = new Proxy();
// 执行方法
proxy.getExpress();
}
}
运行结果
***********************jdk动态代理模式实现 *******************
下面使用jdk动态代理,代理类就由java来维护了,我们使用java提供的Proxy.newProxyInstance()方法来获取代理对象。静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成。
抽象主题代码
/**
* 抽象主题类:这个接口是(真实主题)目标对象和(代理类)代理对象都要共同实现的接口
*/
public interface Subject {
// 定义拿快递的方法
void getExpress();
}
真实主题代码
/**
* 具体主题:(目标对象)
*/
public class GetPackage implements Subject{
// 实现了拿快递的方法
@Override
public void getExpress() {
System.out.println("拿了快递...");
}
}
代理工厂类
// 代理工厂
public class ProxyFactory {
// 聚合具体主题
private GetPackage getPackag = new GetPackage();
// 获取代理对象
public Subject getProxy() {
return (Subject) Proxy.newProxyInstance(
GetPackage.class.getClassLoader(), // 目标对象类加载器
GetPackage.class.getInterfaces(), // 接口的字节码
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* Object proxy:代理对象,这个参数我们一般不用
* Method method:要去调用目标类的哪个方法
* Object[] args:方法的参数
*/
// 通过反射去调用目标对象的方法
Object result = method.invoke(getPackag, args);
// 帮客户买烟
System.out.println("拿买了一包电杆(中华的别名)...");
// 如果要调用的方法有返回值,就返回真实的返回值,没有返回值,就返回null
return result;
}
}
);
}
}
代理模式的应用场景:例如防火墙当数据包进出我们的电脑的时候,代理模式在中间可以帮我们做一些鉴别数据包是否有害。spring aop 中也是代理模式思想实现的面向切面编程,可以动态为方法进行增强。
动态代理还有一种实现方式CGlib感兴趣的可以自行学习。