金三银四面试题(二十一):代理模式知多少?

2024-04-18 21:20

本文主要是介绍金三银四面试题(二十一):代理模式知多少?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

代理模式在软件开发中是一个非常重要的设计模式之一。它提供了一种灵活的方式来控制和管理对象的访问,并且可以在访问对象前后执行额外的操作。

什么是代理模式

代理模式是一种结构型设计模式,其目的是为其他对象提供一种代理以控制对这个对象的访问。代理对象通常充当客户端与真实对象之间的中介,客户端通过代理对象访问真实对象,从而可以在访问前后进行一些额外的控制、管理或者操作。

代理模式通常包括以下角色:

  1. 抽象主题(Subject):声明真实对象和代理对象的共同接口,这样客户端可以通过这个接口访问真实对象或代理对象。

  2. 真实主题(Real Subject):定义了代理所代表的真实对象,客户端最终想要访问的对象。

  3. 代理(Proxy):保存一个引用使得代理可以访问实体,并且提供一个与真实主题相同的接口,这样代理就可以替代真实主题。

代理模式通常有以下几种常见的应用场景:

  • 远程代理(Remote Proxy):用于代表不同地址空间中的对象。通过远程代理,客户端可以访问远程服务器上的对象。

  • 虚拟代理(Virtual Proxy):用于代表比较消耗资源的对象。虚拟代理延迟加载(lazy initialization)真实对象,直到客户端真正需要访问它为止。

  • 保护代理(Protection Proxy):用于控制对对象的访问。保护代理可以根据调用者的身份、权限等条件决定是否允许访问对象的某些方法。

  • 缓存代理(Cache Proxy):用于提高系统的性能。缓存代理在第一次访问真实对象时,将结果缓存起来,以后的访问可以直接返回缓存的结果,避免重复执行相同的操作。

代理模式能够有效地提供额外的控制和管理,同时也能够提供更好的性能和资源利用。

例子

生活中的例子

  • 黄牛卖火车票:没有流行网络购票的年代是很喜欢找黄牛买火车票的,因为工作忙的原因,没时间去买票,然后就托黄牛给你买张回家过年的火车票。这个过程中黄牛就是代理人,火车票就是被代理的对象。

  • 婚姻介绍所:婚姻介绍所的工作人员,搜集单身人士信息,婚介所的工作人员为这个单身人士找对象,这个过程也是代理模式的生活案例。对象就是被代理的对象。

动态代理和静态代理

动态代理和静态代理都是代理模式的两种实现方式,它们都用于控制对对象的访问,并在访问对象前后执行额外的操作,但它们的实现方式和特点有所不同。

  1. 静态代理

    • 静态代理是在编译时期就已经确定了代理类和真实类的关系,代理类是通过手动编码实现的。
    • 在静态代理中,代理类和真实类通常都要实现同一个接口,代理类中包含了对真实对象的引用,并且在方法调用前后执行额外的操作。
    • 静态代理的一个缺点是如果要代理的对象过多,可能会导致代理类的数量过多,增加了代码的复杂性和维护成本。
  2. 动态代理

    • 动态代理是在运行时动态生成代理类的方式实现的,它允许在运行时动态地创建代理对象。
    • 在动态代理中,代理类是由代理工厂根据指定的接口和方法来动态生成的,并在方法调用时通过方法拦截器来执行额外的操作。
    • 动态代理的一个优点是可以减少代码量,因为代理类是动态生成的,不需要手动编写大量的代理类。同时,动态代理也更加灵活,可以代理任意的接口和类,不受静态代理中接口的限制。

总的来说,静态代理在编译时期确定了代理关系,适用于一些固定且较少变化的场景,而动态代理在运行时动态生成代理类,适用于需要灵活处理对象的访问和操作的场景。在 Java 中,JDK 动态代理和 CGLIB 动态代理是两种常见的动态代理实现方式,它们都能够实现在运行时动态生成代理类,并在方法调用时执行额外的操作。

spring中的动态代理

在 Spring 框架中,动态代理是 AOP(面向切面编程)的一个重要实现方式之一。AOP 允许开发者在程序运行期间动态地将额外的逻辑(称为切面)织入到现有的代码中,而动态代理正是实现这一功能的一种手段。

Spring 中的动态代理主要基于 JDK 动态代理和 CGLIB(Code Generation Library,代码生成库)两种技术。下面分别简要介绍这两种动态代理的实现方式:

  1. JDK 动态代理

    • JDK 动态代理是通过反射机制在运行时动态创建代理类的方式实现的。它要求目标对象必须实现一个或多个接口,然后基于这些接口创建代理对象。
    • 在 Spring 中,当目标对象实现了接口时,Spring 会使用 JDK 动态代理来创建代理对象。代理对象会实现目标对象所实现的接口,并在方法调用时委托给 InvocationHandler 来处理。
  2. CGLIB 动态代理

    • CGLIB 动态代理是通过继承目标对象并重写其方法的方式实现的。它不要求目标对象必须实现接口,可以对任意的类进行代理。
    • 在 Spring 中,当目标对象没有实现接口时,Spring 会使用 CGLIB 动态代理来创建代理对象。代理对象会继承目标对象,并在方法调用时通过方法拦截器(MethodInterceptor)来处理。

Spring 中动态代理的实现主要依赖于 Proxy 类和 ProxyFactory 工厂类。Spring 提供了两种方式来创建代理对象:基于接口的 JDK 动态代理和基于类的 CGLIB 动态代理。在使用 Spring AOP 时,开发者可以选择合适的代理方式来实现切面功能,并通过配置文件或注解来指定切面的切入点和通知类型。这样就可以在程序运行期间动态地将切面织入到目标对象的方法调用中,实现各种横切关注点的功能,例如日志记录、性能监控、事务管理等。

代码实现

静态代理

// 定义接口
interface Calculator {int add(int a, int b);
}// 实现接口的类
class CalculatorImpl implements Calculator {@Overridepublic int add(int a, int b) {return a + b;}
}// 代理类
class CalculatorProxy implements Calculator {private final Calculator target;public CalculatorProxy(Calculator target) {this.target = target;}@Overridepublic int add(int a, int b) {// 在方法调用前执行额外的操作System.out.println("Before method invocation");// 调用真实对象的方法int result = target.add(a, b);// 在方法调用后执行额外的操作System.out.println("After method invocation");return result;}
}public class Main {public static void main(String[] args) {// 创建真实对象Calculator calculator = new CalculatorImpl();// 创建代理对象Calculator proxy = new CalculatorProxy(calculator);// 使用代理对象调用方法int result = proxy.add(3, 4);System.out.println("Result: " + result);}
}

动态代理

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 定义接口
interface Calculator {int add(int a, int b);
}// 实现接口的类
class CalculatorImpl implements Calculator {@Overridepublic int add(int a, int b) {return a + b;}
}// 实现 InvocationHandler 接口来处理方法调用
class CalculatorInvocationHandler implements InvocationHandler {private final Calculator target;public CalculatorInvocationHandler(Calculator target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 在方法调用前执行额外的操作System.out.println("Before method invocation");// 调用真实对象的方法Object result = method.invoke(target, args);// 在方法调用后执行额外的操作System.out.println("After method invocation");return result;}
}public class Main {public static void main(String[] args) {// 创建真实对象Calculator calculator = new CalculatorImpl();// 创建动态代理对象Calculator proxy = (Calculator) Proxy.newProxyInstance(Calculator.class.getClassLoader(),new Class<?>[]{Calculator.class},new CalculatorInvocationHandler(calculator));// 使用代理对象调用方法int result = proxy.add(3, 4);System.out.println("Result: " + result);}
}

这篇关于金三银四面试题(二十一):代理模式知多少?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/915868

相关文章

高效+灵活,万博智云全球发布AWS无代理跨云容灾方案!

摘要 近日,万博智云推出了基于AWS的无代理跨云容灾解决方案,并与拉丁美洲,中东,亚洲的合作伙伴面向全球开展了联合发布。这一方案以AWS应用环境为基础,将HyperBDR平台的高效、灵活和成本效益优势与无代理功能相结合,为全球企业带来实现了更便捷、经济的数据保护。 一、全球联合发布 9月2日,万博智云CEO Michael Wong在线上平台发布AWS无代理跨云容灾解决方案的阐述视频,介绍了

2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题

题库来源:安全生产模拟考试一点通公众号小程序 2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题是由安全生产模拟考试一点通提供,流动式起重机司机证模拟考试题库是根据流动式起重机司机最新版教材,流动式起重机司机大纲整理而成(含2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题参考答案和部分工种参考解析),掌握本资料和学校方法,考试容易。流动式起重机司机考试技

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme