专栏首页IT笔记分享设计模式(四)——代理模式

设计模式(四)——代理模式

代理模式

定义:为其他对象提供一种代理以控制对这个对象的访问

上图中,Subject是一个抽象类或者接口,RealSubject是实现方法类,具体的业务执行,Proxy则是RealSubject的代理,直接和client接触的。

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

代理模式优点

  • 职责清晰
  • 高扩展,只要实现了接口,都可以用代理。
  • 智能化,动态代理。

分类

代码:GitHub

1、静态代理

以租房为例,我们一般用租房软件、找中介或者找房东。这里的中介就是代理者。

首先定义一个提供了租房方法的接口。

public interface IRentHose {    void rentHose();}

定义租房的实现类

public class RentHose implements IRentHose {    @Override    public void rentHose() {        System.out.println("租了一间房子。。。");    }}

我要租房,房源都在中介手中,所以找中介

public class IntermediaryProxy implements IRentHose {    private IRentHose rentHose;    public IntermediaryProxy(IRentHose irentHose){        rentHose = irentHose;    }    @Override    public void rentHose() {        System.out.println("交中介费");        rentHose.rentHose();        System.out.println("中介负责维修管理");    }}

这里中介也实现了租房的接口。

再main方法中测试

public class Main {    public static void main(String[] args){        //定义租房        IRentHose rentHose = new RentHose();        //定义中介        IRentHose intermediary = new IntermediaryProxy(rentHose);        //中介租房        intermediary.rentHose();    }}

返回信息

交中介费租了一间房子。。。中介负责维修管理

这就是静态代理,因为中介这个代理类已经事先写好了,只负责代理租房业务

2、强制代理

如果我们直接找房东要租房,房东会说我把房子委托给中介了,你找中介去租吧。这样我们就又要交一部分中介费了,真坑。

来看代码如何实现,定义一个租房接口,增加一个方法。

public interface IRentHose {    void rentHose();    IRentHose getProxy();}

这时中介的方法也稍微做一下修改

public class IntermediaryProxy implements IRentHose {    private IRentHose rentHose;    public IntermediaryProxy(IRentHose irentHose){        rentHose = irentHose;    }    @Override    public void rentHose() {        rentHose.rentHose();    }    @Override    public IRentHose getProxy() {        return this;    }}

其中的getProxy()方法返回中介的代理类对象

我们再来看房东是如何实现租房:

public class LandLord implements IRentHose {    private IRentHose iRentHose = null;    @Override    public void rentHose() {        if (isProxy()){            System.out.println("租了一间房子。。。");        }else {            System.out.println("请找中介");        }    }    @Override    public IRentHose getProxy() {        iRentHose = new IntermediaryProxy(this);        return iRentHose;    }    /**     * 校验是否是代理访问     * @return     */    private boolean isProxy(){        if(this.iRentHose == null){            return false;        }else{            return true;        }    }}

房东的getProxy方法返回的是代理类,然后判断租房方法的调用者是否是中介,不是中介就不租房。

main方法测试:

    public static void main(String[] args){        IRentHose iRentHose = new LandLord();        //租客找房东租房        iRentHose.rentHose();        //找中介租房        IRentHose rentHose = iRentHose.getProxy();        rentHose.rentHose();    }}
请找中介租了一间房子。。。

看,这样就是强制你使用代理,如果不是代理就没法访问。

3、动态代理

我们知道现在的中介不仅仅是有租房业务,同时还有卖房、家政、维修等得业务,只是我们就不能对每一个业务都增加一个代理,就要提供通用的代理方法,这就要通过动态代理来实现了。

中介的代理方法做了一下修改

public class IntermediaryProxy implements InvocationHandler {    private Object obj;    public IntermediaryProxy(Object object){        obj = object;    }    /**     * 调用被代理的方法     * @param proxy     * @param method     * @param args     * @return     * @throws Throwable     */    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        Object result = method.invoke(this.obj, args);        return result;    }}

在这里实现InvocationHandler接口,此接口是JDK提供的动态代理接口,对被代理的方法提供代理。其中invoke方法是接口InvocationHandler定义必须实现的, 它完成对真实方法的调用。动态代理是根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理就会实现接口下所有的方法。通过 InvocationHandler接口, 所有方法都由该Handler来进行处理, 即所有被代理的方法都由 InvocationHandler接管实际的处理任务。

这里增加一个卖房的业务,代码和租房代码类似。

main方法测试:

public static void main(String[] args){    IRentHose rentHose = new RentHose();    //定义一个handler    InvocationHandler handler = new IntermediaryProxy(rentHose);    //获得类的class loader    ClassLoader cl = rentHose.getClass().getClassLoader();    //动态产生一个代理者    IRentHose proxy = (IRentHose) Proxy.newProxyInstance(cl, new Class[]{IRentHose.class}, handler);    proxy.rentHose();    ISellHose sellHose = new SellHose();    InvocationHandler handler1 = new IntermediaryProxy(sellHose);    ClassLoader classLoader = sellHose.getClass().getClassLoader();    ISellHose proxy1 = (ISellHose) Proxy.newProxyInstance(classLoader, new Class[]{ISellHose.class}, handler1);    proxy1.sellHose();}
租了一间房子。。。买了一间房子。。。

在main方法中我们用到了Proxy这个类的方法,

public static Object newProxyInstance(ClassLoader loader,                                          Class<?>[] interfaces,                                          InvocationHandler h)

loder:类加载器,interfaces:代码要用来代理的接口, h:一个 InvocationHandler 对象 。

InvocationHandler 是一个接口,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。

public interface InvocationHandler {    public Object invoke(Object proxy, Method method, Object[] args)        throws Throwable;}

InvocationHandler 内部只是一个 invoke() 方法,正是这个方法决定了怎么样处理代理传递过来的方法调用。

因为,Proxy 动态产生的代理会调用 InvocationHandler 实现类,所以 InvocationHandler 是实际执行者。

总结

  1. 静态代理,代理类需要自己编写代码写成。
  2. 动态代理,代理类通过 Proxy.newInstance() 方法生成。
  3. JDK实现的代理中不管是静态代理还是动态代理,代理与被代理者都要实现两样接口,它们的实质是面向接口编程。CGLib可以不需要接口。
  4. 动态代理通过 Proxy 动态生成 proxy class,但是它也指定了一个 InvocationHandler 的实现类。

本文分享自微信公众号 - IT笔记分享(xiaosen_javashare),作者:xiaosen L

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-03-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 设计模式(一)——单例模式

    在实际生产的项目中我们一般很少自己使用单例模式,但是在有过间接的使用过他,例如spring的bean单例。 定义:确保某一个类只有一个实例,而且自行实例化并向整...

    小森啦啦啦
  • 设计模式(五)——装饰器

    在装饰模式中, 必然有一个最基本、 最核心、 最原始的接口或抽象类充当 Component抽象构件。

    小森啦啦啦
  • Java多线程学习(六)——Lock的使用

    锁是用于通过多个线程控制对共享资源的访问的工具。通常,锁提供对共享资源的独占访问:一次只能有一个线程可以获取锁,并且对共享资源的所有访问都要求首...

    小森啦啦啦
  • Java中的深复制和浅赋值

    深复制和浅复制也称为深拷贝和浅拷贝。简单的说就是创建一个和当前对象一模一样的对象。在日常编码的过程中使用的几率并不多,但在面试中却会被经常问到。

    老九学堂-小师弟
  • Memcached基础了解

    老七Linux
  • Android 之游戏开发流程

    一、概述 刚开始接触Android平台,之前也没有游戏开发经验,因此对于如何开发一款游戏没有思路,而且也不知道如何对整个项目进行模块划分。在学习连连看的教程时,...

    小灰灰
  • 并发基础——多线程

    打开网易云音乐,可以理解为一个进程,然后点开一首歌曲,这是一个线程,然后在播放歌曲的同时,可以在下边评论,这就是两个线程。

    Noneplus
  • 教你如何在 IDEA 远程 Debug ElasticSearch

    之前在 源码阅读环境搭建文章 中写过我遇到的一个问题迟迟没有解决,也一直困扰着我。问题如下,在启动的时候解决掉其他异常和报错后,最后剩下这个错误一直解决不了:

    zhisheng
  • 工厂模式(Factory Design Patter)

    定义一:Define an interface for creating an object, but let subclasses decide which ...

    刘开心_1266679
  • 自定义FutureTask实现

    FutureTask是Future的实现类,用来异步任务的获取结果,可以启动和取消异步任务,查询异步任务是否计算结束以及获取最终的异步任务的结果。通过get()...

    CodingDiray

扫码关注云+社区

领取腾讯云代金券