侧边栏壁纸
博主头像
DJ's Blog博主等级

行动起来,活在当下

  • 累计撰写 133 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

【设计模式】动态代理示例

Administrator
2022-03-18 / 0 评论 / 0 点赞 / 73 阅读 / 5474 字

【设计模式】动态代理示例

需求

目前有新旧两个业务:

  1. 旧业务:买家调用action购买衣服,衣服在数据库的标价为50元,所以直接返回50元。购买流程就是简单的调用。
  2. 新业务:衣服在原先的价格上可以使用优惠券,买家调用action购买衣服并使用优惠券10元,返回衣服的价格为40元。

分析

  1. 在旧业务中,我们用action调用service的方法实现业务即可。
  2. 但是在新业务中,由于之前在service中实现的业务不能够满足当前客户的要求,我们需要重新修改service中的方法,但是service的方法不只在我们这个模块使用,在其他模块也在调用,其他模块调用的时候,现有的service方法已经能够满足业务需求,所以我们不能只为了我们的业务而修改service,导致其他模块受影响。
  3. 那怎么办呢?我们可以通过动态代理的方式,扩展我们的service中的方法实现,使得在原有的方法中增加更多的业务,而不是实际修改service中的方法,这种实现技术就叫做动态代理。

改造过程

  • 书写代理类和代理方法,在代理方法中实现代理Proxy.newProxyInstance
  • 代理中需要的参数分别为
  1. 被代理类的类加载器:someObjectclass.getClassLoader()
  2. 被代理类的所有实现接口:new Class[] { Interface.class }
  3. 被代理类的委托类:new InvocationHandler()
  • 在被代理类的委托类中复写invoke方法,之后想要调用被代理类的方法时,都会委托给这个类的invoke方法
  • 在这个方法中,我们可以定制化的开发新的业务。invoke方法的输入有3个参数
  1. 代理类对象:Object proxy
  2. 被代理类的方法:Method method
  3. 被代理类方法的传入参数:Object[] args
  • 获取代理类,强转成被代理的接口
  • 最后,我们可以像没被代理一样,调用接口的任何方法,方法被调用后,方法名和参数列表将被传入代理类的invoke方法中,进行新业务的逻辑流程。

示例代码

业务接口

/**
 * 这是一个业务的接口,这个接口中的业务就是返回衣服的价格
 * @author dj4817
 * @version $Id: IBoss.java, v 0.1 2017/12/3 9:32 dj4817 Exp $$
 */
public interface IBoss {
    /**
     * 衣服的价格
     * @param size
     * @return
     */
    int yifu(String size);
}

业务接口实现类

/**
 * 衣服销售业务实现类
 * @author dj4817
 * @version $Id: Boss.java, v 0.1 2017/12/3 9:34 dj4817 Exp $$
 */
public class Boss implements IBoss {
    /**
     * 衣服的价格
     * @param size
     * @return
     */
    @Override
    public int yifu(String size) {
        System.out.println("天猫小强旗舰店,老板给客户发快递----衣服型号:" + size);
        // 这件衣服的价钱,从数据库读取
        return 50;
    }
}

原业务逻辑

/**
 * 销售业务
 * @author dj4817
 * @version $Id: SaleAction.java, v 0.1 2017/12/3 9:36 dj4817 Exp $$
 */
public class SaleAction {
    public static void main(String[] args) {
        IBoss boss = new Boss();
        System.out.println("老板自营!");
        // 老板自己卖衣服,不需要客服,结果就是没有聊天记录
        int money = boss.yifu("xxl");
        System.out.println("衣服成交价:" + money);
    }
}

新业务逻辑

/**
 * 代理销售业务
 * @author dj4817
 * @version $Id: ProxySaleAction.java, v 0.1 2017/12/3 9:38 dj4817 Exp $$
 */
public class ProxySaleAction {
    public static void main(String[] args) {
        // 将代理的方法实例化成接口
        IBoss boss = ProxyUtil.getProxyBoss(10, Boss.class);
        System.out.println("代理经营!");
        // 调用接口的方法,实际上调用方式没有变
        int money = boss.yifu("xxl");
        System.out.println("衣服成交价:" + money);
    }
}

新业务逻辑中获取代理类工具

/**
 * 代理获取
 *
 * @author dj4817
 * @version $Id: ProxyUtil.java, v 0.1 2017/12/3 9:39 dj4817 Exp $$
 */
public class ProxyUtil {
    /**
     * 获取Boss的代理对象
     * @param discountCoupon 优惠金额
     * @param implementClass 被代理类
     * @param <T>
     * @return
     */
    public static <T> T getProxyBoss(int discountCoupon, Class<?> implementClass) {
        // 被代理类的类加载器
        ClassLoader classLoader = implementClass.getClassLoader();
        // 被代理类的所有实现接口
        Class<?>[] interfaces = implementClass.getInterfaces();
        Object object = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("Proxy invoke begin");
                System.out.println("proxy: " + proxy.getClass().getName());
                System.out.println("method: " + method.getName());
                for (Object o : args) {
                    System.out.println("arg: "+ o);
                }
                // 被代理类的实例
                Object implement = implementClass.newInstance();
                Integer result = (Integer) method.invoke(implement, args);
                System.out.println("Proxy invoke end");
                return result - discountCoupon;
            }
        });
        return (T) object;
    }
}
0

评论区