设计模式 - 代理模式

代理模式:属于结构型设计模式,有2种写法,根据代理对象创建的时期不同分为是静态代理模式动态代理模式两种

  • 静态代理由开发人员或特定工具自动生成源代码,再对其编译,在程序运行之前 ,代理类已经生成了;
  • 动态代理在程序运行时,利用java的反射机制动态创建而成。

代理模式有几个特点:

  • 代理类和被代理类都是实现同样的接口
  • 代理类本身并不真正实现服务
  • 代理类和被代理类存在关联关系,一个代理类对象和一个被代理类对象相关联
  • 代理类主要是为被代理类进行预处理消息,过滤消息,时候处理消息等等

静态代理模式

举个例子:现在是在中学体育课上,你是一名学生,在这节课上要参加跑步考试
先把跑步员给搞出来:

public interface IRunner {
    void run();
}
public class Runner implements IRunner{
    @Override
    public void run() {
        //身为一个参加跑步考试的学生,你唯一的任务就是跑,其他的都不应该管
        System.out.println("跑步");
        try {
            //跑了5秒钟跑完了
            sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

好了,到了这里,学生已经明白了自己的任务了。但是,考试总得有成绩吧,那么成绩怎么来呢?是让学生自己记录吗?那当然不可能,这时候,一个关键人物就出现了“体育老师”,体育老师会拿着秒表代替我们进行时间记录。
所以,来个老师:

public class Teacher implements IRunner{
    IRunner runner;

    public Teacher(IRunner _runner) {
        this.runner = _runner;
    }

    @Override
    public void run() {
        long start = System.currentTimeMillis();
        System.out.println("老师手握秒表代替学生计时 -> 跑步开始计时:"+ start);
        runner.run();
        long end = System.currentTimeMillis();
        System.out.println("老师手握秒表代替学生计时 -> 跑步结束计时:"+end);
        System.out.println("耗时:"+((int)(end - start)/1000) +"秒");
    }
}

好了,现在老师和学生都准备好了,跑步考试开始

public class Client {
    public static void main(String[] args) {
        IRunner proxy = new Teacher(new Runner());
        proxy.run();
    }
}

结果:
在这里插入图片描述
以上整个过程就有运用到了静态代理模式,老师这个角色就是代理人,他是给学生代理计时的,而学生只需要管自己的事,跑好步就行。代理模式的代理类主要是对被代理对象增加一些与代理对象无关的功能,就像上面的例子一样,跑步考试,学生只管跑就好了,计时就交给老师就完事了。

动态代理模式

对于有多个类都需要进行代理的时候,静态代理模式就不太适合了,毕竟每个类都要建一个对应的代理了,那么就会产生大量的代理类。而且,要实现静态代理,首先要清楚知道要代理的真实对象是谁,不然就一脸懵逼了。所以这时候该动态代理模式登场了。在使用动态代理时,需要用到jdk为我们提供的InvocationHandler接口和Proxy类。

还是使用上面的例子,把它改写为动态代理的模式

首先得来实现一个InvocationHandler接口:

public class ProxyHandler implements InvocationHandler {

    private Object object;

    public ProxyHandler(Object _object) {
        this.object = _object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("老师手握秒表代替学生计时 -> 跑步开始计时:"+ start);
        method.invoke(object,args);
        long end = System.currentTimeMillis();
        System.out.println("老师手握秒表代替学生计时 -> 跑步结束计时:"+end);
        System.out.println("耗时:"+((int)(end - start)/1000) +"秒");
        return null;
    }
}

然后在调用地方进行修改,通过Proxy动态生成代理类

public class Client {
    public static void main(String[] args) {
        //静态代理模式调用
        /*
        IRunner proxy = new Teacher(new Runner());
        proxy.run();
        */

        //动态代理模式调用
        IRunner runner = new Runner();
        ProxyHandler handler = new ProxyHandler(runner);
        //生成代理
        IRunner proxy = (IRunner) Proxy.newProxyInstance(runner.getClass().getClassLoader(), runner.getClass().getInterfaces(),handler);
        proxy.run();
    }
}

运行结果:
在这里插入图片描述

这时候,原来的静态代理类中的Teacher类已经是没用了,因为这是一个在静态代理模式下必须的代理对象,在动态代理模式下,已经交由JDK去生成代理类了。

额外

除了静态代理动态代理之外,还有强制代理透明代理等等一系列适应不同场景的写法,均可在网上找到对应的资料。或者后续有时间我会补充在本篇中。

最后

如果有什么错误的请指正,让我学习一波,互相促进,互相学习!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值