设计模式之代理模式笔记

news2024/11/14 6:36:42

设计模式之代理模式笔记

  • 说明
  • Proxy(代理)
  • 目录
  • 代理模式静态代理示例类图
    • 买火车票的接口
    • 火车站类
    • 代售点类
    • 测试类
  • JDK动态代理
    • 买火车票的接口
    • 火车站类
    • 获取代理对象的工厂类
    • 测试类
  • CGLIB动态代理
    • 火车站类
    • 代理工厂类
    • 测试类
  • 三种代理对比
  • 优缺点

说明

记录下学习设计模式-代理模式的写法。JDK使用版本为1.8版本。

Proxy(代理)

意图:为其他对象提供一种代理以控制对这个对象的访问。
结构:
`

其中:

  • Proxy保存一个引用使得代理可以访问实体;提供一个与Subject的接口相同的接口,使代理可以用来代替实体;控制对实体的存取,并可能负责创建和删除它。
  • Subject定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
  • RealSubject定义Proxy所代表的实体。

适用性:

  • 远程代理为一个对象在不同地址空间提供局部代表。
  • 需代理根据需要创建开销很大的对象。
  • 保护代理控制对原始对象的访问,用于对象应该有不同的访问权限的时候。
  • 智能引用取代了简单的指针,它在访问对象时执行一些附加操作。

目录

在这里插入图片描述

代理模式静态代理示例类图

在这里插入图片描述

以该UML类图实现静态代理模式示例。

买火车票的接口

package com.example.deesign_patterns.proxy.static_proxy;

//买火车票的接口
public interface SellTickets {

    void sell();
}

火车站类

package com.example.deesign_patterns.proxy.static_proxy;

//火车站类
public class TrainStation implements SellTickets{

    @Override
    public void sell() {
        System.out.println("火车站卖票");
    }
}

代售点类

package com.example.deesign_patterns.proxy.static_proxy;

//代售点类
public class ProxyPoint implements SellTickets{

    //声明火车站类对象,将TrainStation类(部分)聚合到ProxyPoint类(整体)里面
    private TrainStation trainStation=new TrainStation();

    @Override
    public void sell() {
        System.out.println("代理点收取一些服务费用");
        trainStation.sell();
    }
}

测试类

package com.example.deesign_patterns.proxy.static_proxy;

//测试类
public class Client {

    public static void main(String[] args) {
        //创建代售点类对象
        ProxyPoint proxyPoint=new ProxyPoint();
        //调用方法进行买票
        proxyPoint.sell();
    }
}

在这里插入图片描述

JDK动态代理

Java中提供了一个动态代理类Proxy,通过提供一个创建代理对象的静态方法(newProxyInstance方法)来获取代理对象。

买火车票的接口

package com.example.deesign_patterns.proxy.jdk_proxy;

//买火车票的接口
public interface SellTickets {

    void sell();
}

火车站类

package com.example.deesign_patterns.proxy.jdk_proxy;

//火车站类
public class TrainStation implements SellTickets {

    @Override
    public void sell() {
        System.out.println("火车站卖票");
    }
}

获取代理对象的工厂类

package com.example.deesign_patterns.proxy.jdk_proxy;

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

//获取代理对象的工厂类
public class ProxyFactory {

    //声明目标对象
    private TrainStation trainStation=new TrainStation();

    //获取代理对象的方法
    public SellTickets getProxyObject(){
        //返回代理对象
        /*
        newProxyInstance方法三个参数说明:
        ClassLoader loader:类加载器,用于加载代理类。可以通过目标对象来获取类加载器
        Class<?>[] interfaces:代理类实现的接口的字节码对象
        InvocationHandler h:代理对象的调用处理程序
         */
        SellTickets proxyObject = (SellTickets)Proxy.newProxyInstance(
                trainStation.getClass().getClassLoader(),
                trainStation.getClass().getInterfaces(),
                new InvocationHandler() {
                    /*
                    Object proxy:代理对象。和proxyObject对象是同一个对象,在invoke方法中基本不用。
                    Method method:对接口中的方法进行封装的method对象
                    Object[] args:调用方法的实际参数,如果sell方法有参数,这里的参数就是sell方法的参数,本案例中sell没有参数
                    返回值:方法的返回值,本案例中sell方法没有返回值
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代售点收取一定的服务费用(jdk动态代理)");
                        //执行目标对象的方法,通过反射的形式调用
                        Object obj = method.invoke(trainStation, args);
                        return obj;
                    }
                }
        );
        return proxyObject;
    }
}

测试类

package com.example.deesign_patterns.proxy.jdk_proxy;

//测试类
public class Client {

    public static void main(String[] args) {
        //获取代理对象
        //1.创建代理工厂对象
        ProxyFactory factory = new ProxyFactory();
        //2.使用factory对象的方法获取代理对象
        SellTickets proxyObject = factory.getProxyObject();
        //3.调用卖票方法
        proxyObject.sell();
    }
}

在这里插入图片描述

CGLIB动态代理

如果pom.xml中有如下依赖,可直接使用cglib代理

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

如没有该依赖,添加这个依赖即可:

		<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

火车站类

package com.example.deesign_patterns.proxy.cglib_proxy;

//火车站类
public class TrainStation{

    public void sell() {
        System.out.println("火车站卖票");
    }
}

代理工厂类

package com.example.deesign_patterns.proxy.cglib_proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

//代理对象工厂,用来获取代理对象
public class ProxyFactory implements MethodInterceptor {

    //声明目标对象
    private TrainStation trainStation=new TrainStation();

    public TrainStation getProxyObject(){
        //创建Enhancer对象,类似于JDK代理中的Proxy类
        Enhancer enhancer=new Enhancer();
        //设置父类的字节码对象
        enhancer.setSuperclass(TrainStation.class);
        //设置回调函数
        enhancer.setCallback(this);
        //创建代理对象
        TrainStation proxyObject = (TrainStation) enhancer.create();
        return proxyObject;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代售点收取一定的服务费用(cglib代理)");
        //要调用目标对象的方法,使用反射的形式调用
        Object obj = method.invoke(trainStation, objects);
        return obj;
    }
}

测试类

package com.example.deesign_patterns.proxy.cglib_proxy;

//测试类
public class Client {

    public static void main(String[] args) {
        //创建代理工厂对象
        ProxyFactory factory=new ProxyFactory();
        //获取代理对象
        TrainStation proxyObject = factory.getProxyObject();
        //调用代理对象中的sell方法卖票
        proxyObject.sell();
    }
}

在这里插入图片描述

三种代理对比

jdk代理和cglib代理

  • 使用cglib实现动态代理,cglib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在jdk1.6之前比使用java反射效率要高。唯一需要主要的是,cglib代理不能对声明为final的类或者方法进行代理,因为cglib原理是动态生成被代理类的子类。
  • 在jdk1.6,jdk1.7,jdk1.8逐步对jdk动态代理优化之后,在调用次数较少的情况下,jdk代理效率高于cglib代理,只有当进行大量调用的时候,jdk1.6和jdk1.7比cglib效率低一点,但是到jdk1.8的时候,jdk代理效率高于cglib代理。所以如果有接口使用jdk动态代理,如果没有接口使用cglib动态代理。

动态代理和静态代理

  • 动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
  • 如果接口增加一个方法,静态代理模式除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。而动态代理不会出现该问题。

优缺点

优点:

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

缺点:
增加了系统的复杂度。

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

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

相关文章

windows pwn

环境搭建 checksec winchecksec winchecksec 是 windows 版的 checksec &#xff0c;不过有时候结果不太准确。 checksec&#xff08;x64dbg&#xff09; x64dbg 的插件 checksec 检查效果比较准确&#xff0c;并且可以连同加载的 dll 一起检测。 将 release 的插件按 3…

RK3288 Android8.1添加EC25

首先拿到供应商提供的so库&#xff0c;将so放到vendor\rockchip\common\phone\lib下 修改对应的phone.mk&#xff0c;将so库移动指定位置&#xff08;Android7以下移动到system/lib,android8以后移动到vendor/lib&#xff09; CUR_PATH : vendor/rockchip/common#############…

mysql避免重复插入记录insert ignore 、on duplicate key update、replace into

星标▲Java学习之道▲一起成长&#xff0c;一起学习~ 哈喽&#xff0c;大家好&#xff0c;我是阿淼。今天梳理一下mysql中避免重复插入记录的集中操作。 1序 回顾以前写的项目&#xff0c;发现在规范的前提下&#xff0c;还是可以做点骚操作的。 假如项目使用的MySQL&#xff0…

基于Informer的股票价格预测(量化交易综述)

摘要 股票市场是金融市场中不可或缺的组成部分。准确预测股票趋势对于投资者和市场参与者具有重要意义&#xff0c;因为它们可以指导投资决策、优化投资组合以及降低金融风险。而且可以提升国家国际地位以及金融风险控制能力&#xff0c;还可以促进股票市场发展以及资源优化利…

Java常用类库与技巧

1、String&#xff0c;StringBuffer&#xff0c;StringBuilder的区别&#xff1f; 2、Java异常 异常处理机制主要回答了三个问题 What&#xff1a;异常类型回答了什么被抛出&#xff1f;Where&#xff1a;异常堆栈跟踪回答了在哪抛出&#xff1f;Why&#xff1a;异常信息回答…

PowerDesigner165安装

PowerDesigner安装及解析 一、PowerDesigner安装1.双击开始安装2.一路“Next”3.选择地区4.安装路径5.按图勾选6.一路“Next”7.安装中8.安装完成 二、解析三、使用 一、PowerDesigner安装 1.双击开始安装 2.一路“Next” 3.选择地区 选择软件安装所属地区,一定要选择“Hong …

vue3-实战-12-管理后台-权限管理之菜单管理模块-首页-主题颜色-暗黑模式

目录 1-列表页面功能开发 1.1-需求原型分析 1.2-接口和数据类型定义 1.3-获取服务端数据渲染页面 2-新增编辑菜单 2.1-原型需求分析 2.2-表单数据收集和页面结构开发 2.3-提交或者取消 3-删除菜单 4-首页开发 5-暗黑模式的切换和主题颜色 5.1-暗黑模式 5.2-主题颜…

three.js几何体的_UV_、法向属性以及BufferGeometry类介绍

一、几何体的_UV_以及法向属性 UV属性是一组二维坐标&#xff0c;每个顶点都有一个对应的UV坐标。在三维模型上贴上二维的纹理贴图时&#xff0c;需要将所有顶点映射到纹理上的对应位置。UV属性的取值范围一般是[0,1]&#xff0c;表示纹理上的相对位置。通过修改UV属性&#xf…

Shell - 02_shell变量

一、shell的自定义变量 1.定义变量&#xff1a;变量名变量值 如&#xff1a;num10 2.引用变量&#xff1a;$变量名 如&#xff1a;i$num 把变量 num 的值付给变量 i 3.显示变量&#xff1a;使用 echo 命令可以显示单个变量取值 如&#xff1a;echo $num 4.清除变量&…

如何写好接口自动化测试脚本

谈到接口测试&#xff0c;大家关注更多的是哪个工具更优秀&#xff0c;更好用。但是很少人关注到接口测试用例的设计问题&#xff0c;也很少人会去写接口用例&#xff0c;都代码化了嘛&#xff0c;还写什么用例&#xff0c;是吧&#xff1f; 这样真的对么&#xff1f;我们是不…

Web3通过 MetaMask简单演示对ganache虚拟环境账号进行管理操作

上文 Web3通过ganache运行起一个本地虚拟区块链 我们通过ganache在本地运行起了一个虚拟的区块链环境 那么 接下来 我们就要用 MetaMask 来管理这个东西了 如果您还没有安装 可以访问文章Web3 将 MetaMask添加入谷歌浏览器 扩展程序中和Web3开发准备工作 手把手带你创建自己的 …

行业报告 | 人工智能时代的营销新趋势

原创 | 文 BFT机器人 01 科技推动时代发展进步 随着电子计算机的发明和使用&#xff0c;打开了人类知识的全方位信息时空&#xff0c;人类由此从工业文明走进信息文明&#xff0c;渐渐地网络成为了人们进行社会活动的基本平台。 智能手机的出现将人们剩余的碎片化时间也连接到了…

从尾到头打印链表

输入一个链表的头节点&#xff0c;按链表从尾到头的顺序返回每个节点的值&#xff08;用数组返回&#xff09;。 如输入{1,2,3}的链表如下图: ​ 返回一个数组为[3,2,1] 0 < 链表长度 < 10000 示例1 输入&#xff1a; {1,2,3} 返回值&#xff1a; [3,2,1]示例2 输入…

springboot集成J-IM+vue实现简单的聊天功能

前言&#xff1a;看了demo自己摸索着集成了一下&#xff0c;特此记录 一、引入依赖 <!-- jim-server --> <dependency><groupId>org.j-im</groupId><artifactId>jim-server</artifactId><version>3.0.0.v20200501-RELEASE&l…

【系统开发】尚硅谷 - 谷粒商城项目笔记(六):异步线程池

文章目录 异步线程池讲解简单线程池常见的四种线程池进阶线程池为什么使用线程池异步编排基本用法其他API线程串行化两任务组合都完成时一个完成时 多任务组合 异步线程池讲解 简单线程池 public class Test01 {public static void main(String[] args) {// 声明一个有10个线…

Java——集合

文章目录 1、集合概述2、集合类体系结构Collection集合体系 3、Collection集合常用API3、Collection集合的遍历方式方式一&#xff1a;迭代器方式二&#xff1a;foreach/增强for循环方式三&#xff1a;lambda表达式 4、List系列集合List集合特点和特有APILinkedList集合 5、集合…

物流园仓库智能综合监控系统

现代经济的不断发展&#xff0c;仓储物流业也在快速地发展&#xff0c;物流仓库作为物质资源的存储和转运&#xff0c;在经济生产中发挥着重大的作用&#xff0c;但是在此期间&#xff0c;随之而来的是物品丢失、被盗、损坏等一系列安全隐患事件。 物流仓库里面存储物品的多数都…

nginx: client intended to send too large body

最近上传大于1M文件的时候&#xff0c;报错nginx。 413 Request Entity Too Large 经过排查修改nginx配置 这是最简单的一个做法&#xff0c;着报错原因是nginx不允许上传配置过大的文件&#xff0c;那么件把nginx的上传大小配置调高就好。 1、打开nginx主配置文件nginx.co…

【性能测试】loadrunner12.55教程(一)--知识准备

目录 1.0. 前言 1.1 性能测试术语介绍 1.1.1 响应时间&#xff08;Response time&#xff09; 1.1.2 并发用户数 1.1.3 吞吐量&#xff08;Throughput&#xff09; 1.1.4 吞吐率&#xff08;Throughout&#xff09; 1.1.5 TPS&#xff08;Transaction Per Second&#x…

深度复盘:那些曾在618一鸣惊人的新品牌,今天过得怎么样?

分析师&#xff1a;yolo 编辑&#xff1a;yolo 出品&#xff1a;增长黑盒研究组 *本报告为增长黑盒独立研究系列&#xff0c; 与第三方不存在任何利益关系 从各平台的活动力度上来看&#xff0c;这届618堪称“史上最卷”&#xff1a;不装了&#xff0c;直接摊牌降价促销。 然而…