当前位置: 首页 > article >正文

Java代理模式详解:从原理到实践

文章目录

  • 前言
  • 一、什么是代理?
  • 二、代理的目的
  • 三、如何实现代理?
  • 四、实现代理的模式
    • 1.静态代理
      • 实现步骤
      • 结果
      • 静态代理的优缺点
    • 2.动态代理(基于接口的动态代理)
      • 实现步骤
      • 结果
      • 动态代理的优缺点
  • 总结


前言

在软件开发中,设计模式是解决常见问题的经典方案,而代理模式作为结构型设计模式的重要成员,广泛应用于各种场景中。无论是日志记录、权限校验,还是延迟加载、远程调用,代理模式都能在不修改原始代码的情况下,优雅地扩展功能。Java作为一门面向对象的编程语言,提供了多种实现代理的方式,包括静态代理和动态代理。本文将深入探讨代理模式的核心概念、实现方式及其应用场景,帮助读者全面理解并掌握这一强大的设计模式。


一、什么是代理?

  • 在软件开发中,代理模式是一种结构型设计模式,它给目标对象提供一个代理对象,并且有代理对象控制着目标对象的引用。
  • 代理模式的核心目的是在不改变原始类代码的情况下,增强或扩展其功能。代理对象通常会在调用被代理对象的方法之前或之后执行一些额外的操作,例如日志记录、权限校验、延迟加载等。

二、代理的目的

代理模式的主要目的包括:

  1. 增强功能:在不修改原始类的情况下,通过代理对象添加额外的功能。
  2. 控制访问:通过代理对象限制对原始对象的直接访问,例如权限校验。
  3. 解耦:将核心逻辑与附加功能分离,提高代码的可维护性和可扩展性。

三、如何实现代理?

在Java中,代理模式的实现主要分为两种方式:静态代理和动态代理。下面我们将详细探讨这两种实现方式。

四、实现代理的模式

1.静态代理

静态代理是指在编译时就已经确定代理类和被代理类的关系。代理类和被代理类通常实现相同的接口或继承相同的父类,代理类在调用被代理类的方法前后可以添加额外的逻辑。

实现步骤

  1. 定义一个接口(或抽象类),声明需要代理的方法。
  2. 创建被代理类,实现该接口。
  3. 创建代理类,同样实现该接口,并在方法中调用被代理类的方法,同时添加额外的逻辑。
//1.定义接口
interface ByClothes {
    abstract void clothes(String size);
}
//2.创建被代理类
class ClothesFactory implements ByClothes{
   public void clothes(String size){
       System.out.println("已经给您定制好了一件大小为"+size+"的衣服");
   }
   public void 机器处理(){
   }
   public void 原材料(){}
}
//3.创建代理类
class Proxy implements ByClothes {
   private ClothesFactory clothesFactory = new ClothesFactory();
   @Override
   public void clothes(String size) {
       FrontService();
       clothesFactory.clothes(size);
       endService();
   }
   //前置服务
   public void FrontService() {
       System.out.println("根据您的需求进行市场调研");
   }
   //前置服务
   public void endService() {
       System.out.println("为您提供一条龙的包办服务");
   }
}
//测试
public class Test {
   public static void main(String[] args) {
       Proxy proxy = new Proxy();
       proxy.clothes("xxxL");
   }
}

结果

在这里插入图片描述

静态代理的优缺点

  • 优点:简单直观,易于理解和实现。
  • 缺点:每个被代理类都需要一个对应的代理类,代码冗余,不易扩展。

2.动态代理(基于接口的动态代理)

动态代理是指在运行时动态生成代理类,而不是在编译时确定。

实现步骤

  1. 定义一个接口,声明需要代理的方法。

  2. 创建被代理类,实现该接口。

  3. 创建InvocationHandler实现类,在invoke()方法中添加额外逻辑。

  4. 使用Proxy.newProxyInstance()方法创建代理对象。

//1.定义接口
 interface ByClothes {
     abstract void clothes(String size);
}
//2.创建被代理类
 class ClothesFactory implements ByClothes{
    public void clothes(String size){
        System.out.println("已经给您定制好了一件大小为"+size+"的衣服");
    }
    public void 机器处理(){
    }
    public void 原材料(){}
}
// 3. 创建InvocationHandler实现类
 class DyProxy implements InvocationHandler {
    //被代理的对象
    //代理对象如何得知自己代理的是哪个目标类
    //这里这样写其实是让用户告诉我,我要代理谁
    private Object o ;
    public DyProxy(Object o){
        this.o = o;
    }


    //2.获取目标类的接口,要知道自己代理的核心方法是啥?
    public Object getProxyInterFace(){
        return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(),this);
    }

    //知道了接口----》变相得知了自己要代理的核心方法:
    //invoke方法是利用反射的方式获取到了要代理的核心方法
    //1.Object:jdk创建的代理类,无需赋值
    //2.Method:目标类当中的方法,jdk提供,无需赋值
    //3.Object[]:目标类当中的方法的参数,jdk提供,无需赋值
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        FrontService();

        method.invoke(o,args);

        endService();
        return null;
    }
    //前置服务
    public void FrontService() {
        System.out.println("根据您的需求进行市场调研");
    }
    //前置服务
    public void endService() {
        System.out.println("为您提供一条龙的包办服务");
    }

}
//测试
public class Test1 {
    public static void main(String[] args) {
        ClothesFactory clothesFactory = new ClothesFactory();
        ByClothes clothes = (ByClothes) new DyProxy(clothesFactory).getProxyInterFace();
        clothes.clothes("XXXL");
}}

结果

在这里插入图片描述

动态代理的优缺点

  • 优点:无需为每个被代理类编写代理类,代码更简洁,易于扩展。
  • 缺点:只能代理实现了接口的类。

总结

代理模式是Java中一种强大的设计模式,能够在不修改原始类的情况下增强其功能。静态代理简单直观,但扩展性较差;动态代理则更加灵活,适用于复杂的场景。无论是静态代理还是动态代理,都可以通过代理对象控制对被代理对象的访问,从而实现功能的扩展和解耦。

在实际开发中,动态代理(尤其是JDK动态代理)被广泛应用于框架和库中,例如Spring AOP。掌握代理模式的原理和实现方式,对于理解Java高级特性和框架设计具有重要意义。


http://www.kler.cn/a/553086.html

相关文章:

  • 整理一些安装环境的常用命令
  • Huatuo热更新--如何使用
  • 优先队列(典型算法思想)—— OJ例题算法解析思路
  • 打破限制!自定义 Hooks 如何提升 React 组件的灵活性
  • 用户坐标系(ucs)与系统坐标系(wcs)的转换详解——CAD c#二次开发
  • 【AI工程实践】阅文集团:NLP在网络文学领域的应用
  • Java Spring boot 篇:常用注解
  • 数智驱动:医学编程与建模技术在智慧医院AI建设中的创新与变革
  • floodfill算法系列一>衣橱整理
  • 4.7 模型训练基类Trainer:Hugging Face工业级训练引擎深度剖析
  • 安装mmdet3d报错【fatal error: spconv/maxpool.h: No such file or directory】
  • `fi` 是 Bash 脚本中用来结束 `if` 条件语句块的关键字
  • firefox升级后如何恢复收藏夹和密码的问题
  • SPO(Self-Supervised Prompt Optimization)自我监督Prompt提示优化的全景指南
  • 机器人路径规划 | 基于极光PLO优化算法的机器人三维路径规划Matlab代码
  • 【嵌入式Linux应用开发基础】特殊进程
  • 机试刷题_矩阵的最小路径和【python】
  • 7.【线性代数】——求解Ax=0,主列和自由列
  • Spring Cloud环境搭建
  • 【数据结构】队列(Queue)