• 设计模式——代理模式(Proxy)


    定义

    为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。(结构型)
    
    如果不知道代理模式,可能大家对代理服务器都不叫熟悉。代替服务器代替请求者去发一起对另一个服务器的请求,他相当于请求的中间人。为什么要通过这个代理呢,那是因为客户端直接去访问服务器会被拒绝(防火墙屏蔽),而代理服务器则可以直接访问服务器。这里有两种应用场景,一种是国内的翻墙了(静态代理),另一种是hacker想掩盖自己的ip时,往往会通过多层代理服务器进行访问/或者不停的切换代理(动态代理,《who am i》电影里面男主就是通过代理去和另外一个haacker通信,而且所用的代理一直在变防止被追踪到)
    

    模板

    代理模式

    抽象角色(Subject)
    通过接口或抽象类声明真实角色实现的业务方法。

    代理角色(RealSubject)
    实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作

    真实角色(Proxy)
    实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用

    实例

    a) 静态代理
    静态代理
    Main中去调用ProxyPrinter中的print方法而不需要关心被代理类(Printer),由于代码比较简单,这里就不具体展开。

    b) 动态代理
    这里列举了一个可以将任何方法的执行放在指定线程(提前创建好的UI线程和后台线程)的动态代理实现,具体如下:
    动态代理

    假如一个有一个写文件的操作类如下:

    public class FileWriter {
    
        private void writeBytesToFile(String fileName, Byte[] bytes) {
           // 将二进制文件写入到 文件中
        }
    }
    

    做过前端开发的应该都知道写文件是一个耗时操作,不能在主线程中执行,那我们现在怎么办?

    FileWriter fileWriter = new FileWriter();
    FileWriter proxyWriter = ObjectThreadProxy.back(fileWriter, FileWriter.class);
    proxyWriter.writeBytesToFile("TestFile.txt", xxxx);
    

    上述代码通过前面讲的ObjectThreadProxy工具类就可以将被代理的对象转换成proxyWriter,接下来调用proxyWriter的任何方法都会执行在子线程中。这是如何做到的,具体看一下back方法及ThreadInvocationHandler就知道了:

    // back 方法中创建代理类
    ThreadInvocationHandler handler = new ThreadInvocationHandler(realObj, syncMode);
    Object proxyObj = Proxy.newProxyInstance(class.getClassLoader(), new Class[]{class}, handler);
    return proxyObj;
    
    
    // ThreadInvocationHandler 中invoke方法关键代码如下:
    public Object invoke(Object proxy, final Method method, final Object[] args) {
        switch(mode) {
            case BACK:
                // 在子线程执行方法
                method.invoke(readObject, args);
                break;
            case MAIN:
                // 在主线程中执行
                break;
    }
    

    优点

    1.代理模式能将代理对象与真实对象被调用的目标对象分离,一定程度上降低了系统的耦合度,扩展性好。
    2.保护目标对象。
    3.增强目标对象。

    缺点

    1. 创建多个类,增加代码阅读复杂性(所有设计模式通病)
    2. clone方法只是浅拷贝,除五种基础类型之外类型都只是简单的指向引用,不会重新创建成员变量,如需实现需要自定义clone方法。
    3. 通过clone方法不会调用类的构造函数,部分场景(在构造函数中做一些初始化操作的)需要做额外的处理

    适用场景

    1.保护目标对象
    2.增强目标对象

    与装饰模式的区别

    对对象的作用
    装饰者:动态的新增或组合对象的行为,在不改变接口的前提下,动态扩展对象的功能
    代理模式:为其他对象提供一种代理以控制对这个对象的访问,在不改变接口的前提下,控制对象的访问

    如何使用该对象
    装饰者:通常将原始对象作为参数传递给Decorator的构造函数。
    代理模式:代理类中创建一个真实对象的实例
    注: 其实代理模式也可以作为参数传递,这里是网上很多地方的写法,自己并不赞同。

    模式的核心
    装饰者:强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。增强后你还是你,只不过能力更强了而已
    代理模式:强调要让别人去做一些本身和你业务没有太多关系的职责(记录日志,设置缓存,远程代理负责网络通信的一些细节),代理模式是为了实现对对象的控制,因为被代理的对象往往难以直接获得或者其内部不想暴露出来

    其它实例:

    待补充

  • 相关阅读:
    Node Sass could not find a binding for your current environment : Node.js 8.x -SpiritMark
    SpringBoot从入门到精通教程(八)
    注解 @CrossOrigin
    出现VMware Workstation 无法连接到虚拟机。请确保您有权运行该程序、访问该程序使用的所有目录以及访问所有临时文件目录。 未能将管道连接到虚拟机: 所有的管道范例都在使用中。
    说一下 JSP 的 4 种作用域?
    jsp有哪些内置对象?作用分别是什么?
    MVC的各个部分都有那些技术来实现?如何实现?
    你所了解的的软件测试类型都有哪些,简单介绍一下。
    你的测试职业发展目标是什么?
    您认为做好测试用例设计工作的关键是什么?
  • 原文地址:https://www.cnblogs.com/NeilZhang/p/11962927.html
Copyright © 2020-2023  润新知