• 设计模式之代理模式


    定义

       为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 或者在一系列功能模块中加入一些扩展的功能模块,那个时候就会用到面向切面编程(AOP),其中就是用的代理。

    角色

    • 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

    • 目标对象角色:定义了代理对象所代表的目标对象。

    • 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象

    分类

    • 远程代理:也就是为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。这个不同的地址空间可以是在本机器上,也可以在另一台机器中。

      远程代理模式的实现

    • 虚拟代理:是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象,使其只有在真正需要时才被创建。
    • 安全代理:也叫保护代理,用来控制真实对象访问时的权限,如果有必要的话,可以给不同调用者提供不同的权限。
    • 智能指引:是指当调用真实对象时,代理处理另外一些事,比如记录对此对象的调用次数等。
    • 写时拷贝:虚拟代理的一种,把复制推迟到只有客户的需要时才进行。
    • 缓存代理:为某一个目标的操作结果提供临时存储空间,以便其他客户的可以共享访问,有点缓存的味道。
    • 防火墙代理:保护对象,不让用户访问,安全代理的特例。
    • 同步代理:可以让几个用户同时访问同一个对象而不产生冲突。

      其中最常用的就是前四种。

    优点

     职责清晰

        被代理对象只负责自己实际的业务逻辑,不关心其他非本身的职责。并将其他事务可以通过代理类处理。

    高扩展性
        无论被代理对象如何改变,只要代理类和被代理类都实现了统一接口,都不同修改代理类,而且即使扩展了新的被代理类,代理类也可以使用,只要创建代理类的时候传入对应的被代理类对象。

    智能化
        这主要体现在动态代理中,下面会讲解动态代理。如果有兴趣了解Spring的AOP,其实就是使用了动态代理。

    缺点

       1.由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,从而降低并发量。

      2.实现代理模式需要额外的工作,这会导致资源的消耗,如果复杂的代理模式可能会降低系统性能。

    适用场景

       1.需要保护目标类,不希望直接被调用;
      2.设置权限。类似Spring AOP的使用。

    实现方式

    • 静态代理 

        继承法:代理类直接继承被代理类,实现其原有方法,并添加一些额外功能

      聚合法:代理类实现相同的功能接口(很重要,相同接口,不同代理也可以进行相互代理),并在内声明一个被代理类的对象(类似封装),通过内部对象实现其原有方法,并添加额外功能

    
    
        代理类在程序运行前就编译好,因此称为静态代理。代理对象和被代理对象都要实现相同的接口或者继承相同的父类(除Object之外),一旦接口或者父类添加、修改方法,子类都要统一更改,违背开闭原则,因此静态代理具有一定的局限性。
      如果我们要实现功能的叠加,比如增加方法运行时间处理,增加权限管理,增加日志处理等,或者调整这些功能的实现顺序,如果有一百种实现顺序,我们用继承法就要实现100个代理子类,这显然是不现实的,如果需要修改也是极其繁琐的。
    而如果使用聚合法,只要一个代理类管理一个功能,在维护和调整顺序上都是最优的。所以现实中聚合法笔继承法更好。
    • 动态代理

      jdk代理:弥补了静态代理需要子类继承或者实现父类的缺点,利用反射机制创建对象,进一步降低了耦合度。动态代理必须依赖接口的实现,但并不是所有的目标对象都会继承父类或者实现接口。

      cfLab代理弥补了JDK动态代理不足。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,来完成动态代理的实现。但由于CGLib采用动态创建子类的方法,对于final方法,无法进行代理。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)。

      注意:使用Cglib代理需要引入Cglib的jar包,而且还需要引入asm-all的jar包。注意两个包的版本号,因为不同的版本可能不兼容导致报错。

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>asm</groupId>
        <artifactId>asm-all</artifactId>
        <version>3.3</version>
    </dependency>
    <!--这里只是举个例子,具体的版本对应要自己去寻找-->

    装饰者模式和代理模式的区别

      装饰者模式主要是为了增强被装饰者类的功能,可以说是继承的一种替代方案。 隐藏了被装饰者类的具体实现,对于调用方来说只知道装饰者类。

      代理模式主要是为了增强被代理类的权限控制。隐藏了被代理类具体实现,对于调用方来说只知道代理类。

      装饰者模式和代理模式的实现机制都很像,但是为什么一样的机制要区分出2种设计模式呢?可以说是为了单一职责原则不被破坏。因为2个模式的具体职责不一样,如果都叫装饰者模式或者都叫代理模式那么开发人员就区分不出来具体的作用。对于区分出2种职责可以说为了更加容易理解吧!

    适配器模式和代理模式的区别

      适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

    代码

    动态代理实现原理

  • 相关阅读:
    log4j配置
    Fragment配合RadioGroup实现点击切换布局
    (转)[原] Android 自定义View 密码框 例子
    标题栏透明度变化
    Android 监听ScrollView的滑动
    Android进度条学习
    Android-正方形的容器
    Android添加图片到ListView或者 RecyclerView显示
    Android打开相机和打开相册
    2020新年快乐
  • 原文地址:https://www.cnblogs.com/htyj/p/12779825.html
Copyright © 2020-2023  润新知