一、什么是代理模式?
在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象
代理模式的定义与特点
由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
代理模式的主要优点有:
- 代理模式会造成系统设计中类的数量增加
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
- 增加了系统的复杂度;
二、代理模式分类
1.静态代理模式
这里我们就以买红薯为例写一个代码
第一步:先写一个接口(抽象角色)
一般会使用接口或者抽象类来解决
代码如下(示例):
//卖红薯
public interface SweetPotato {
void sellsweetpotato();
}
第二步:创建一个农民类继承该接口(真实角色)
被代理的角色
代码如下(示例):
//农民
public class farmer implements SweetPotato {
@Override
public void sellsweetpotato() {
System.out.println("卖红薯");
}
}
这时我们要吃烤红薯的话,不会直接去找农民买红薯,而是找卖烤红薯的老板,这里的老板就是代理角色
第三步:创建代理角色
代理真实角色,后一般会做一些附属操作
代码如下(示例):
//红薯店老板
public class boss implements SweetPotato {
private farmer farmer1;
public boss() {
}
public void setFarmer1(farmer farmer1) {
this.farmer1 = farmer1;
}
@Override
public void sellsweetpotato() {
farmer1.sellsweetpotato();
roast();
}
public void roast() {
System.out.println("老板烤红薯");
}
}
这里烤红薯就是代理角色的附属操作
第四步:创建客户端用来访问代理角色
代码如下(示例):
public class me extends boss {
public static void main(String[] args) {
farmer farmer = new farmer();
boss boss = new boss();
boss.setFarmer1(farmer);
boss.sellsweetpotato();
}
}
优缺点
优点:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共业务交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
缺点:
按照上面的案例如果我要买板栗,还要重新创建一个卖板栗的代理角色,这样代码量会翻倍,开发效率会变低
为了避免这种缺点,我们可以用动态代理模式
2.动态代理模式
在程序运行时,运用反射机制动态创建而成
java动态代理机制中有两个重要的类和接口InvocationHandler(接口)和Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心;
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。
Proxy类就是用来创建一个代理对象的类
接着上面的案例,用动态代理模式再实现一遍
第一步和第二步和前面的一样
第三步:
代码如下(示例):
//老板
public class boss implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//动态代理的本质,就是使用反射机制实现
Object result = method.invoke(target, args);
return result;
}
//添加一个日志的功能
public void log(String msg) {
System.out.println("执行了"+msg+"方法");
}
}
这里并没有生成代理类
第四步:
public class me extends boss {
public static void main(String[] args) {
//真实角色
farmer1 farmer = new farmer1();//✅
boss boss = new boss();
//通过调用程序处理角色来处理我们要调用的接口对象
boss.setTarget(farmer);//设置代理的对象
//动态生成代理类
chestnut proxy = (chestnut) boss.getProxy();//✅
proxy.sellchestnut();
}
}
如果要将红薯改为板栗直接修改代码中✅标记的地方即可
好处:
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可