八、代理模式

news2024/10/7 6:47:01

一、什么是代理模式

  代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

  代理模式的主要角色如下:

  • 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

二、代理模式的实现

  根据代理的创建时期,代理模式分为静态代理和动态代理。

  • 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
  • 动态代理:在程序运行时,运用反射机制动态创建而成,可通过InvocationHandler或者cglib实现。

1、静态代理

  • 抽象主题(Subject)类:
/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/2 0002 18:28
 * @description (静态代理)抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
 */
public interface Subject {
    void doSomething();
}
  • 真实主题(Real Subject)类:
/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/2 0002 18:29
 * @description (静态代理)真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
 */
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("处理一些事情..............");
    }
}

  • 代理(Proxy)类:

/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/2 0002 18:30
 * @description (静态代理)代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能
 */
public class Proxy implements Subject {
    private Subject subject;
    public Proxy(Subject subject){
        this.subject = subject;
    }
    @Override
    public void doSomething() {
        if (subject==null){
            subject = new RealSubject();
        }
        beforeDoSomething();
        subject.doSomething();
        afterDoSomething();
    }

    private void afterDoSomething() {
        System.out.println("afterDoSomething............");
    }

    private void beforeDoSomething() {
        System.out.println("beforeDoSomething...............");
    }
}

2、通过InvocationHandler实现动态代理

  • 动态代理(InvocationHandler)抽象主题(Subject)类:
/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/3 0003 9:56
 * @description (动态代理)抽象主题(Subject)类:通过接口或抽象类来声明真实主题和代理对象实现的业务方法
 */
public interface DynamicSubject {
    void doSomething();
}

  • 动态代理(InvocationHandler)真实主题(real subject)类:

/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/3 0003 9:59
 * @description (动态代理)真实主题(real subject)类:实现了抽象主题的具体业务实现,是代理对象所代理的真实对象,是最终要引用的对象。
 */
public class DynamicRealSubject implements DynamicSubject {
    @Override
    public void doSomething() {
        System.out.println("在这里处理一些业务.................");
    }
}

  • 动态代理(InvocationHandler)代理(Proxy)类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/3 0003 10:04
 * @description (动态代理)代理(Proxy)类:对真实主题功能的扩展
 */
public class DynamicProxy implements InvocationHandler {
    //需要代理的对象
    private DynamicSubject dynamicSubject;

    /**
     * 构造方法
     * @param dynamicSubject 要代理的对象
     */
    public DynamicProxy(DynamicSubject dynamicSubject){
        this.dynamicSubject = dynamicSubject;
    }

    /**
     *
     * @param proxy 被代理的类
     * @param method 要增强的方法
     * @param args 增强的方法参数
     * @return 增强的方法返回值
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始增强..................");
        System.out.println("增强的方法是..."+method.getName());
        if (args!=null&&args.length>0){
            for (Object arg : args) {
                System.out.println(arg.toString());
            }
        }
        Object invoke = method.invoke(dynamicSubject, args);
        System.out.println("增强结束..................");
        return invoke;
    }

    /**
     * 获取被代理的对象
     * @return 被代理的对象
     */
    public DynamicSubject getDynamicSubject() {
        return dynamicSubject;
    }

    /**
     * 获取代理后增强的对象
     * @param dynamicSubject 被代理的对象
     * @return 代理后增强的对象
     */
    public static DynamicSubject newInstance(DynamicSubject dynamicSubject) {
        InvocationHandler invocationHandler = new DynamicProxy(dynamicSubject);
        return (DynamicSubject) Proxy.newProxyInstance(DynamicSubject.class.getClassLoader(),
                        new Class[]{DynamicSubject.class},invocationHandler);
    }
}

3、通过cglib实现动态代理

  • (cglib)抽象主题(Subject)类:

/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/3 0003 11:50
 * @description (cglib)抽象主题(Subject)类:通过接口或抽象类来声明真实主题和代理对象实现的业务方法
 */
public interface CglibSubject {
    void doSomething();
}

  • (cglib)真实主题(real subject)类:
/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/3 0003 11:52
 * @description (cglib)真实主题(real subject)类:实现了抽象主题的具体业务实现,是代理对象所代理的真实对象,是最终要引用的对象。
 */
public class CglibRealSubject implements CglibSubject {
    @Override
    public void doSomething() {
        System.out.println("处理自己的业务....................");
    }
}

  • cglib)代理(Proxy)类:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/3 0003 11:53
 * @description (cglib)代理(Proxy)类:对真实主题功能的扩展
 */
public class CglibProxy implements MethodInterceptor {
    private CglibSubject cglibSubject;

    public CglibProxy(CglibSubject cglibSubject) {
        this.cglibSubject = cglibSubject;
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("增强....................");
        Object invoke = methodProxy.invokeSuper(o, objects);
        System.out.println("增强结束..................");
        return invoke;
    }

    public static CglibSubject newInstance(CglibSubject cglibSubject){
        CglibProxy cglibProxy = new CglibProxy(cglibSubject);
        Enhancer enhancer = new Enhancer();//帮我们生成代理对象
        enhancer.setSuperclass(CglibRealSubject.class);//设置对谁进行代理
        enhancer.setCallback(cglibProxy);//代理要做什么
        return (CglibSubject) enhancer.create();//创建代理对象
    }

}

4、测试类


/**
 * @author FluffyCatkin
 * @version 1.0
 * @date 2020/1/2 0002 17:55
 * @description 代理模式
 *
 *在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。
 *
 * 在软件设计中,使用代理模式的例子也很多,例如,要访问的远程对象比较大(如视频或大图像等),其下载要花很多时间。还有因为安全原因需要屏蔽客户端直接访问真实对象,如某单位的内部数据库等。
 * 代理模式的定义与特点:
 * 代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
 *
 * 代理模式的主要优点有:代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
 * 代理对象可以扩展目标对象的功能;
 * 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
 *
 * 其主要缺点是:在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
 * 增加了系统的复杂度;
 * 代理模式的结构与实现:
 * 代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构和实现方法。
 * 模式的结构:
 * 代理模式的主要角色如下。抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
 * 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
 * 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
 *
 *  静态代理  动态代理  CGLIB代理
 *
 */
public class Main {
    /**
     * 测试静态代理
     */
    @Test
    public void staticProxyTest(){
        Subject subject = new RealSubject();
        Proxy proxy = new Proxy(subject);
        proxy.doSomething();
    }

    /**
     * 测试动态代理
     */
    @Test
    public void dynamicTest(){
        DynamicSubject dynamicSubject = DynamicProxy.newInstance(new DynamicRealSubject());
        dynamicSubject.doSomething();
    }

    /**
     * cglib代理测试
     */
    @Test
    public void cglibTest(){
        CglibSubject cglibSubject = CglibProxy.newInstance(new CglibRealSubject());
        cglibSubject.doSomething();
    }
}

运行结果:

  • 测试静态代理:

beforeDoSomething...............
处理一些事情..............
afterDoSomething............



Process finished with exit code 0
  • 测试InvocationHandler动态代理:

开始增强..................
增强的方法是...doSomething
在这里处理一些业务.................
增强结束..................



Process finished with exit code 0
  • 测试cglib动态代理:

增强....................
处理自己的业务....................
增强结束..................



Process finished with exit code 0

三、应用场景

  当无法或不想直接引用某个对象或访问某个对象存在困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。

  一般代理模式有以下的应用场景:

  • 远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。
  • 虚拟代理,这种方式通常用于要创建的目标对象开销很大时。例如,下载一幅很大的图像需要很长时间,因某种计算比较复杂而短时间无法完成,这时可以先用小比例的虚拟代理替换真实的对象,消除用户对服务器慢的感觉。
  • 安全代理,这种方式通常用于控制不同种类客户对真实对象的访问权限。
    智能指引,主要用于调用目标对象时,代理附加一些额外的处理功能。例如,增加计算真实对象的引用次数的功能,这样当该对象没有被引用时,就可以自动释放它。
  • 延迟加载,指为了提高系统的性能,延迟对目标的加载。例如,Hibernate 中就存在属性的延迟加载和关联表的延时加载。

四、优缺点分析

  代理模式的主要优点有:

  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  • 代理对象可以扩展目标对象的功能;
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性

  其主要缺点是:

  • 代理模式会造成系统设计中类的数量增加
  • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
  • 增加了系统的复杂度;

代码地址:https://gitee.com/fluffycatkin/JavaDesignModel.git

image.png

原文出处:http://c.biancheng.net/view/1359.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/952019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OutOfMemoryError内存溢出和StackOverFlowError栈溢出及解决方法

前一篇:JVM 内存结构 StackFlowError(栈溢出) 线程的堆栈存储 线程局部原始数据类型、变量、对象的引用、返回值。如果线程堆栈大小超出分配的内存限制,就会出现栈溢出错误。 这里用递归调演示错误 解决方法: 1、修…

初始Linux进程间通信(单机)

目录 1、前言 2、进程间通信的分类 管道 System V IPC POSIX IPC 3、管道 3.1 匿名管道 pipe 实例代码 管道读写规则: 管道特点 3.2 命名管道 创建一个命名管道 两个进程间使用命名管道进行通信示例代码 4、system V共享内存 4.1 共享内存数据结构 …

【档案专题】八、电子档案鉴定与销毁

导读:主要针对电子档案鉴定与销毁相关内容介绍。对从事电子档案管理信息化的职业而言,不断夯实电子档案管理相关理论基础是十分重要。只有通过不断梳理相关知识体系和在实际工作当中应用实践,才能走出一条专业化加职业化的道路,从…

Java虚拟机内部组成

1、栈区 public class Math {public int compute(){//一个方法对应一块栈帧内存区域int a l;int b 2;int c (a b)*10;return c; } public static void main(String[] args){Math math new, Math() ;math.compute() ;System.out.println("test");}} 栈是先进后出…

29 - restful - 套叠结构

套叠结构的两种方式: 1. marshal(数据,返回的格式) 函数 2. marshal_with(加工后的返回格式)装饰器 返回格式必须是符合json格式,如果直接返回不能用自定义的对象:User,Friend... 需要 marchal(),marchal_with()帮助进行转换 一. 定义模型类 一. marshal(数据,返回的结构) …

ssh访问远程宿主机的VMWare中NAT模式下的虚拟机

1.虚拟机端配置 1.1设置虚拟机的网络为NAT模式 1.2设置虚拟网络端口映射(NAT) 点击主菜单的编辑-虚拟网络编辑器: 启动如下对话框,选中NAT模式的菜单项,并点击NAT设置: 点击添加,为我们的虚拟机添加一个端口映射。…

java八股文面试[数据库]——MySQL索引的数据结构

知识点: 【2023年面试】mysql索引的基本原理_哔哩哔哩_bilibili 【2023年面试】mysql索引结构有哪些,各自的优劣是什么_哔哩哔哩_bilibili

巨擘科技|国内数据交易现状梳理及典型交易平台对比分析(附建设方案)

近年来,在国家促进要素市场化配置系列政策指导下,各地方政府有关部门单位均在积极探索数据要素市场化运行机制,在推进数据要素价值体系建立、数据要素市场规则构建等工作方面已初具成效。 基于此,本文选取国内相关典型政府主导型的数据交易平台进行案例分析,并揭示其特点…

【高性能计算】opencl语法及相关概念(三)事件,内存

opencl中的事件概念 当谈到OpenCL中的事件时,它们代表了执行的各个阶段或操作的状态信息。通过使用事件,您可以跟踪和管理内核执行以及内存操作的进度和顺序。以下是与OpenCL事件相关的关键概念: 创建事件:您可以使用clCreateUse…

动态数组 Vector(难度1)(V)

C数据结构与算法实现(目录) 前驱课程 C 精简教程 目录(必读) 堆数组 heap array 面相对象的堆数组 1 原始堆数组的缺点: 1) 原始堆数组 其长度是固定不变的。 2) 使用指针管理元素&#…

数据大小无限制!海量倾斜摄影三维模型在线查看及分享

通常,倾斜摄影三维模型数据量都较大,这是由其高精度、对地表全覆盖的真实影像所决定的。如何将海量倾斜摄影模型数据加载到地图中并进行在线查看是行业用户一直关心的内容,现在通过「四维轻云」就可以在线查看及分享倾斜摄影三维模型。 1、倾…

静态类方法的同步

由于在调用静态方法时,对象实例不一定被创建。因此,就不能使用this来同步静态方法,而必须使用Class对象来同步静态方法。代码如下: 通过synchronized块同步静态方法 public class StaticSyncBlock { public static void…

nacos配置超级管理员账户,只能mysql存储数据(或者其他数据库)

nacos本身是不允许授权超级管理员账号的,也就是角色名“ROLE_ADMIN”。作者在页面上试过了,不必再次尝试改的方式是直接改数据库里面的数据

十八、责任链模式

一、什么是责任链模式 责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时&#xff0…

element ui-Pagination

页面分为两个表格,当两边的表格数据量大时,分页样式就会受到影响,可以将跳转按钮的个数减少 页面分页代码如下 页面效果

QT基础教程之七Qt消息机制和事件

QT基础教程之七Qt消息机制和事件 事件 事件(event)是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件在对用户操作做出响应时发出&#xff0c…

【YOLOV5】YOLOV5添加SPPCSPC

当前YOLOV5版本为7.0 第一步 在models/common.py添加SPPCSPC class SPPCSPC(nn.Module):# CSP https://github.com/WongKinYiu/CrossStagePartialNetworksdef __init__(self, c1, c2, n1, shortcutFalse, g1, e0.5, k(5, 9, 13)):super(SPPCSPC, self).__init__()c_ int(2 *…

docker安装及使用-Linux

前提 确保docker支持当前系统版本,docker支持centos 7及以上版本,要求Linux内核版本不低于3.10 cat /etc/redhat-release #查看系统版本 查看内核版本三种方式 cat /proc/version uname -a uname -r 一、安装docker 0、卸载docker(根…

二十一、中介者模式

一、什么是中介者模式 中介者(Mediator)模式的定义:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型…

Linux:ansible-playbook配置文件(剧本)

如果你还没有配置基础的ansible和一些基础用法可以去下面的链接 playbook是基于ansible的 Linux:ansible自动化运维工具_鲍海超-GNUBHCkalitarro的博客-CSDN博客 Linux:ansible自动化运维工具_鲍海超-GNUBHCkalitarro的博客-CSDN博客 Linux&…