定义:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。代理模式分为静态代理、动态代理、CGLIB代理等方式,稍后会举例说明。
1.抽象对象:一般是来声明代理对象和被代理对象之间的公共方法,该类可以是接口,也可以是抽象类。
2.目标对象:又称为被代理类,是真正执行业务逻辑的类
3.代理对象:又称为代理类,此类中一般包含了目标对象的引用,因此具备了目标对象的代理权。并且可以对目标对象进行逻辑增强或控制性操作。
从定义上来看,其实和中介者模式(行为模式)有相似之处,但是具体区分的话,其实在目的,角色划分上是不同的,
1.目的:中介者模式是为了解耦,将访问者与被访问者解耦,避免直接关联;代理模式是为了控制对某对象的访问。
2.角色:中介者模式分为四种角色:抽象中介类、具体中介类、抽象同事类、具体同事类;代理模式分为三种角色:抽象对象、目标对象、代理对象
1.代理模式能将代理对象和目标对象分离
2.在一定程度上降低了系统的耦合,扩展性好
3.可以起到保护目标的作用
4.可以起到增强目标对象的作用
1.请求会先通过代理类,会降低请求效率
2.系统复杂度增加
最常用的场景便是Spring 的AOP了,相信很多同学都用过。
以“点外卖为例”,小王想点一份25块钱西红柿盖浇饭,但是不想出门,于是在外卖平台上点了某个饭店外卖,外卖平台上有满减,满20-2,于是小王只花了23块钱就得到了一份盖浇饭。
分析一下角色分类:
客户:小王;代理类:外卖平台;委托类:饭店
依次举例不同代理分类的代码:
public interface AbstractOrder {
/**
* 下单
*
* @return
*/
Double placeOrder(Integer type);
}
@Getter
@AllArgsConstructor
public enum OrderList {
XI_HONG_SHI_CHAO_DAN(1, "西红柿炒鸡蛋盖饭",new Double(25)),
LA_JIAO_CHAO_ROU(2, "辣椒炒肉盖饭",new Double(20)),
MU_XU_ROU(3, "木须肉肉盖饭",new Double(18));
/**
* 菜单类型
*/
private Integer type;
/**
* 菜单名称
*/
private String name;
/**
* 价格
*/
private Double price;
private static final Map<Integer, OrderList> MAP = Stream.of(OrderList.values())
.collect(Collectors.toMap(OrderList::getType, Function.identity()));
public static OrderList get(Integer type) {
return MAP.get(type);
}
}
public class XiaoWangOrder implements AbstractOrder {
@Override
public Double placeOrder(Integer type) {
OrderList orderList = OrderList.get(type);
System.out.println("小王:我想点一份" + orderList.getName() + "(" + orderList.getPrice() + ")");
return orderList.getPrice();
}
}
public class DeliveryPlatform implements AbstractOrder {
//小王下单
private XiaoWangOrder xiaoWangOrder;
public DeliveryPlatform(XiaoWangOrder xiaoWangOrder) {
this.xiaoWangOrder = xiaoWangOrder;
}
@Override
public Double placeOrder(Integer type) {
System.out.println("使用外卖平台点单:");
Double money = xiaoWangOrder.placeOrder(type);
//判断价格是否大于20元,若大于,优惠2元
if (Double.compare(money, new Double(20)) > 0) {
System.out.println("外卖平台已满20元,优惠2元");
return money - 2;
}
return money;
}
}
public class Client {
public static void main(String[] args) {
//将小王初始化到外卖平台,小王可以点单
DeliveryPlatform platform = new DeliveryPlatform(new XiaoWangOrder());
Double money = platform.placeOrder(OrderList.XI_HONG_SHI_CHAO_DAN.getType());
System.out.println("最终消费金额:" + money);
}
}
测试结果:
抽象类、小王、枚举类不变,变化的是代理类,使用InvocationHandler与Proxy代理类处理,注意包全是java.lang.reflect下面的类。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* DeliveryPlatform
*
* @author zhouxy
* @date 2022/8/5
**/
public class DeliveryPlatform implements InvocationHandler {
private AbstractOrder abstractOrder;
/**
* 获取实例对象
*
* @param abstractOrder
* @return
*/
public AbstractOrder getInstance(AbstractOrder abstractOrder) {
this.abstractOrder = abstractOrder;
Class<?> clazz = abstractOrder.getClass();
//将当前代理类加入到处理下单类的逻辑中,当有访问该abstractOrder的时候,会被invoke方法拦截处理。
return (AbstractOrder) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(abstractOrder, args);
//根据返回结果处理数据
return after((Double) obj);
}
public void before() {
System.out.println("外卖平台开始点单");
}
public Double after(Double price) {
//优惠金额大于20时,则优惠2元
if (Double.compare(price, 20) > 0) {
System.out.println("消费金额大于20,优惠2元");
price = price - 2;
}
System.out.println("外卖平台点单完成");
return price;
}
}
其中,着重解释一下Proxy类,此类为代理类,使用到的为newProxyInstance方法,该方法的作用是:
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
百度翻译:返回指定接口的代理类实例,该接口将方法调用分派给指定的调用处理程序。
根据注释可以很清楚的看出该方法的用处,即将指定的调用程序DeliveryPlatform指定给getInstance方法中的abstractOder类中的方法,在访问该类时,会走DeliveryPlatform中的invoke方法。
public class Client {
public static void main(String[] args) {
DeliveryPlatform deliveryPlatform = new DeliveryPlatform();
AbstractOrder xiaoWangOrder = deliveryPlatform.getInstance(new XiaoWangOrder());
Double price = xiaoWangOrder.placeOrder(OrderList.XI_HONG_SHI_CHAO_DAN.getType());
System.out.println("最终消费:" + price);
}
}
测试结果:
public class DeliveryPlatformCGLIB implements MethodInterceptor {
/**
* 获取实例,是一个字节码增强器,可以用来为委托类创建代理
*
* @param clazz
* @return
*/
public Object getInstance(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
//处理委托类方法
Object obj = methodProxy.invokeSuper(o, objects);
return after((Double) obj);
}
public void before() {
System.out.println("外卖平台开始点单");
}
/**
* 优惠
*
* @param price
* @return
*/
public Double after(Double price) {
//优惠金额大于20时,则优惠2元
if (Double.compare(price, 20) > 0) {
System.out.println("消费金额大于20,优惠2元");
price = price - 2;
}
System.out.println("外卖平台点单完成");
return price;
}
}
public class Client {
public static void main(String[] args) {
DeliveryPlatformCGLIB cglib = new DeliveryPlatformCGLIB();
XiaoWangOrder xiaoWangOrder = (XiaoWangOrder) cglib.getInstance(XiaoWangOrder.class);
Double price = xiaoWangOrder.placeOrder(OrderList.XI_HONG_SHI_CHAO_DAN.getType());
System.out.println("最终消费:" + price);
}
}
测试结果: