定义:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。代理模式分为静态代理、动态代理、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);
- }
- }
-
测试结果: