JAVA 二十三种设计模式大全(十二)代理模式(Proxy Pattern)(三)动态代理

改进(需求)

我们的静态代理,只能代理一个固定的接口。
比如在(二)中,我们写了4个类去实现Movable接口,也就是4个类代理一个类。
那我如果现在多写一个Eatable接口,那我又需要再写4个类去代理它(假如要实现的功能与上面类似时)。
那这样似乎又是在重复堆砌了,能否有一种把所要代理的接口写活的方法呢?
让我们只需要写一次代理类,处处使用?

设计

把上面的需求描述转换一下,其实就是要让我们的代理类不再依附于被代理对象。
举例:
写一个日志代理类LogProxyFactory,它可以给任何类代理,在它们的运行前后添加日志,这样就实现了我们的目的:
不需要为被代理类重复写代理类。
说白了,如下图所示的位置,我们要做解耦。
在这里插入图片描述

代码

注:带$符号的都是代理类

public interface Movable {
    void move();
}
public class PeopleMovable implements Movable {
    // 人物移动是我们的主体行为
    // 理论上来讲,不需要嵌套到外部
    // 不过为了设计合理,也给它嵌套到外部的能力
    private Movable m;

    public PeopleMovable(Movable m) {
        this.m = m;
    }

    public PeopleMovable() {

    }

    @Override
    public void move() {
        if (m != null) {
            m.move();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("人物在移动");
    }
}

public class ProxyFactory {
//    甚至我们可以直接写ProxyFactory
//    而不做具体的日志类型 ,这样我们的代理工厂,可以代理任意类,也可以做任何形式的代理

    private Logger logger = LoggerFactory.getLogger("ProxyFactory");
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getLogTimeProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long start = System.currentTimeMillis();
                        logger.info(this.getClass().getName() + "日志----------》开始");
                        Object invoke = method.invoke(target, args);
                        logger.info(this.getClass().getName() + "日志----------》结束");
                        long end = System.currentTimeMillis();
                        logger.info("耗时{}毫秒", end - start);
                        return invoke;
                    }
                });
    }

    public Object getTimeProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long start = System.currentTimeMillis();
                        Object invoke = method.invoke(target, args);
                        long end = System.currentTimeMillis();
                        logger.info("耗时{}毫秒", end - start);
                        return invoke;
                    }
                });
    }

    public Object getLogProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        logger.info(this.getClass().getName() + "日志----------》开始");
                        Object invoke = method.invoke(target, args);
                        logger.info(this.getClass().getName() + "日志----------》结束");
                        return invoke;
                    }
                });
    }
}

public class MainProxyFactory {
    public static void main(String[] args) {
        // 串行的
        ProxyFactory proxyFactory = new ProxyFactory(new PeopleMovable());
        Movable logProxyInstance = (Movable) proxyFactory.getLogProxyInstance();
        logProxyInstance.move();
        System.out.println("------------------------->");
        Movable timeProxyInstance = (Movable) proxyFactory.getTimeProxyInstance();
        timeProxyInstance.move();
        System.out.println("------------------------->");
        //    再来个先日志后耗时的
        ProxyFactory proxyFactory1 = new ProxyFactory(timeProxyInstance);
        Movable logProxyInstance1 = (Movable) proxyFactory1.getLogProxyInstance();
        logProxyInstance1.move();
        System.out.println("------------------------->");
        //    也可以单独写个,这样调用方便了
        Movable logTimeProxyInstance = (Movable) proxyFactory.getLogTimeProxyInstance();
        logTimeProxyInstance.move();
        //    结果:
        //    09:44:52.800 [main] INFO ProxyFactory - proxypattern.ProxyFactory$3日志----------》开始
        //人物在移动
        //09:44:53.812 [main] INFO ProxyFactory - proxypattern.ProxyFactory$3日志----------》结束
        //------------------------->
        //人物在移动
        //09:44:54.823 [main] INFO ProxyFactory - 耗时1006毫秒
        //------------------------->
        //09:44:54.833 [main] INFO ProxyFactory - proxypattern.ProxyFactory$3日志----------》开始
        //人物在移动
        //09:44:55.839 [main] INFO ProxyFactory - 耗时1006毫秒
        //09:44:55.840 [main] INFO ProxyFactory - proxypattern.ProxyFactory$3日志----------》结束
        //------------------------->
        //09:44:55.847 [main] INFO ProxyFactory - proxypattern.ProxyFactory$1日志----------》开始
        //人物在移动
        //09:44:56.853 [main] INFO ProxyFactory - proxypattern.ProxyFactory$1日志----------》结束
        //09:44:56.854 [main] INFO ProxyFactory - 耗时1007毫秒
    }
}

总结

如上,把任意类的实例对象传入代理工厂,都可以实现代理,目前有日志和耗时,其他的也都可以继续往代理工厂补充。
这样实现了代理类与被代理类的解耦,一次编码处处代理^^

总而言之,代理模式中的动态代理算是设计模式中比较难理解的
主要是利用了java中的
java.lang.reflect.Proxy
这个类

所以也称为JDK动态代理
含义就是这种代理是利用了JDK的API实现的

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值