Java:三种代理模式示例

news2024/12/21 15:24:23

什么是代理模式?

代理(Proxy)是一种设计模式,为其他对象提供一种代理以控制对这个对象的访问。

代理模式的组成

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

代理模式的优点

(1).职责清晰

真实的角色就是实现实际的[业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。

(2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。

(3).高扩展性

代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象。

一、静态代理

步骤1:创建接口 Animal.java

/**
 * 静态代理步骤1
 *  -创建接口
 * */
public interface Animal {

    void run();
    void eat();

}

步骤2:创建实现类并实现步骤1的接口 AnimalImpl.java

/**
 * 静态代理步骤 2
 *  -创建实现类并实现步骤1的接口
 * */
public class AnimalImpl implements Animal{

    @Override
    public void run() {
        System.out.println("猎豹跑的都很快");
    }

    @Override
    public void eat() {
        System.out.println("动物为了生存,一般都喜欢进食");
    }
}

步骤3:创建代理类并实现步骤1的接口 StaticProxy.java

/**
 * 静态代理步骤 3
 *  -创建代理类并实现步骤1的接口
 * */
public class StaticProxy implements Animal{

    private Animal animal;// 目标对象

    // 构造函数
    StaticProxy(){}

    StaticProxy(Animal _animal){
        this.animal = _animal;
    }

    @Override
    public void run() {
        System.out.println("事物开始前");
        animal.run();
        System.out.println("事物开始后");
    }

    @Override
    public void eat() {
        System.out.println("事物开始前");
        animal.eat();
        System.out.println("事物开始后");
    }
}

步骤4:实现代理方法:

/**
 * 静态代理步骤4
 *  -实现静态代理方法
 * */
public class TestMain {
    /**
     * 总结:
     *
     * 静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现接口或继承相同 的父类
     * 缺点:
     *
     * 因为代理对象需要和被代理对象实现相同的接口或父类,所以会有太多的代理类
     * 一旦接口中增加了方法后,被代理对象和代理对象都需要维护(非常麻烦,不方便)
     * */
    public static void main(String[] args) {
        //1.创建目标对象(通过目标实现类创建目标对象)
        Animal animal = new AnimalImpl();

        //2.创建代理对象(将目标对象传递进代理对象,建立代理关系)
        StaticProxy staticProxy = new StaticProxy(animal);

        //3.执行方法
        staticProxy.run();
        staticProxy.eat();
    }

运行结果:

二、JDK动态代理

步骤1:创建接口 Persion.java

/**
 * JDK动态代理步骤1
 *  -创建接口
 * */
public interface Persion {

    void say();

}

步骤2:创建实现类并实现步骤1的接口PersionImpl.java

/**
 * JDK动态代理步骤2
 *  -创建实现类并实现步骤1的接口
 * */
public class PersionImpl implements Persion {
    @Override
    public void say() {
        System.out.println("每个人都有说话的权力!");
    }
}

步骤3:创建动态代理类JDKProxy.java

/**
 * JDK动态代理步骤3
 *  -创建动态代理类
 * */
public class JDKProxy {

    private Persion persion;// 目标对象

    // 构造函数
    public JDKProxy(Persion _persion){
        this.persion = _persion;
    }


    /**
     *  给目标对象生成代理对象
     *
     * JDK中动态代理类只需要使用java.lang.reflect.Proxy.newProxyInstance方法,该方法需要接收三个参数,完整写法:
     * static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
     *
     * ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
     * Class<?>[] interfaces:目标对象实现的接口类型,使用泛型方式确认类型,获取接口类型的方法是固定的
     * InvocationHandler h;事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
     * */
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),persion.getClass().getInterfaces(),this::invoke);
    }


    /**
     * 生成执行目标对象方法
     * */
    public Object invoke(Object proxy, Method method, Object[] args){
        try{
            System.out.println("开始事务");
            //执行目标对象方法
            Object returnValue = method.invoke(persion, args);
            System.out.println("结束事务");
            return returnValue;
        }catch (Throwable  throwable){
            throwable.getLocalizedMessage();
            return null;
        }

    }
}

步骤4:实现代理方法

/**
 * JDK动态代理步骤4
 *  -实现代理方法
 *
 *  测试jdk动态代理
 *      代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
 *      接口中增加方法时只用在实现类中增加方法,不用修改代理类。
 * */
public class JDKMain {

    public static void main(String[] args) {
        // 目标对象
        Persion persion = new PersionImpl();
        // 【原始的类型 class com.jwt.demo.jdkdl.PersionImpl】
        System.out.println(persion.getClass());

        // 给目标对象,创建代理对象
        Persion jdkProxy = (Persion) new JDKProxy(persion).getProxyInstance();
        // class $JDKProxy   内存中动态生成的代理对象
        System.out.println(jdkProxy.getClass());

        // 执行代理方法
        jdkProxy.say();


    }

}

运行结果:

 

三、cglib动态代理

步骤1:引入jar包

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

步骤2:创建被代理的类UserDao.java

public class UserDao{
    public void getUser() {
        System.out.println("cglib动态代理:得到用户信息");
    }
    public void insertUser() {
        System.out.println("cglib动态代理:添加用户");
    }
}

步骤3:创建代理类CglibProxy.java

/**
 * cglib动态代理
 *
 * */
public class CglibProxy implements MethodInterceptor {
    //维护目标对象
    private Object target;
    public CglibProxy (Object target) {
        this.target = target;
    }
    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy         
       methodProxy) throws Throwable {
        System.out.println("开始事务...");
        //执行目标对象的方法
        Object returnValue = method.invoke(target, objects);
        System.out.println("提交事务...");
        return returnValue;
    }
}

步骤4:实现代理方法

public class CglibProxyMain {
    public static void main(String[] args) {
        //目标对象
        UserDao target = new UserDao();
        System.out.println(target.getClass());
        // 给目标对象,创建代理对象
        UserDao proxy = (UserDao) new Proxy03(target).getProxyInstance();
        System.out.println(proxy.getClass());
        proxy.getUser();//执行的是代理的方法
        proxy.insertUser();
    }
}

运行结果:

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

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

相关文章

kibana自动补全功能失效的几个原因

文章目录 不能自动补全index&#xff1f;不能自动补全field&#xff1f; 不能自动补全index&#xff1f; 当用户在 kibana 的 Dev Tools 页面手写查询时&#xff0c;理应可以自动补全 index 的名称&#xff0c;如下图&#xff1a; 如果不能自动补全&#xff0c;则点击 Settin…

【网站项目】295演唱会购票系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

在线绘图利器:支持在线使用的电脑画图软件推荐!

计算机绘图软件是现代设计师和创作者必不可少的工具之一。伴随着技术的不断发展&#xff0c;越来越多的在线计算机绘图软件应运而生&#xff0c;为用户提供了更加便捷、高效的创作方法。对初学者而言&#xff0c;选择一款易于使用、功能强大的计算机绘图软件至关重要。本文将介…

Tomcat服务部署优化

目录 一.Tomcat的基本内容 1.概念 2.构成 &#xff08;1&#xff09;web容器 &#xff08;2&#xff09;servlet容器&#xff08;catalina&#xff09; &#xff08;3&#xff09;JSP容器 3.Tomcat顶层架构 &#xff08;1&#xff09;Tomcat中最顶层的容器是Server&…

DCFL: for Oriented Tiny Object Detection

文章目录 AbstractIntroductionContributionRelated Work定向目标检测微小目标检测多尺度学习标签分配上下文信息特征增强MethodOverview动态先验Coarse Prior MatchingFiner Dynamic Posterior MatchingAblation StudyAnalysis不平衡问题的调解可视化速度Conclusionhh 源代码 …

麒麟KYLINSOS服务器操作系统SP3安装

原文链接&#xff1a;安装麒麟服务器操作系统V10 SP3 在当今的IT环境中&#xff0c;内网仓库的部署对于确保网络安全、加快本地访问速度以及保持软件包的一致性至关重要。特别是对于企业和组织而言&#xff0c;内网仓库可以极大地提升工作效率和系统稳定性。今天&#xff0c;我…

ArmSoM Rockchip系列产品 通用教程 之 CAN 使用

CAN 使用 1. CAN 简介 CAN (controller Area Network)&#xff1a;控制器局域网络总线&#xff0c;是一种有效支持分布式控制或实时控制的串行通信网络。 目前世界上绝大多数汽车制造厂商都采用CAN总线来实现汽车内部控制系统之间的数据通信。 RK3568/RK3588的CAN驱动文件&a…

Effective objective-c-- 内存管理

Effective objective-c-- 内存管理 前言理解引用计数引用计数工作原理属性存取方法中的内存管理自动释放池保留环要点 以ARC简化引用计数使用ARC时必须遵循的方法和命名规则变量的内存管理语义ARC如何清理实例变量覆写内存管理方法要点 在dealloc方法中只释放引用并解除监听要点…

品牌与时间函数:在时间的长河中铸造品牌

品牌推广是一个与时间紧密相连的复杂过程。时间不仅是品牌推广的见证者&#xff0c;更是其推动者和塑造者。迅腾文化深刻理解品牌推广与时间之间的微妙关系&#xff0c;提出的“显”的原则&#xff0c;旨在通过巧妙的策略&#xff0c;使品牌在时间的流转中逐渐显现出其特别的魅…

Less is More: Generating Grounded Navigation Instructions from Landmarks

摘要 我们研究根据室内路线捕获的 360 图像自动生成导航指令。现有的生成器视觉基础较差&#xff0c;导致它们依赖语言先验并对物体产生幻觉。我们的 MARKY-MT5 系统通过关注视觉地标来解决这个问题&#xff1b;它包括第一级地标检测器和第二级生成器——多模式、多语言、多任…

基于springboot实现计算机类考研交流平台系统项目【项目源码+论文说明】

基于springboot实现计算机类考研交流平台系统演示 摘要 高校的大学生考研是继高校的高等教育更上一层的表现形式&#xff0c;教育的发展是我们社会的根本&#xff0c;那么信息技术的发展又是改变我们生活的重要因素&#xff0c;生活当中各种各样的场景都存在着信息技术的发展。…

U盘遇阻?解决“位置不可用”的困扰

U盘遇阻&#xff1a;当“位置不可用”成为难题 在数字化时代&#xff0c;U盘已成为我们存储和传输数据的重要工具。然而&#xff0c;当U盘突然提示“位置不可用”时&#xff0c;这无疑是一个令人头疼的问题。这不仅意味着我们无法访问存储在U盘中的文件&#xff0c;而且可能还…

PlantUML - 时序图

时序图主要内容 下面是一个简单的时序图&#xff0c;我们可以很容易并且美观的表达我们的交互流程&#xff0c;只需要在箭头的两边指定一个名字&#xff0c;加上描述即可&#xff1a; startuml bkloanapply -> bkloanapprove : request bkloanapprove --> bkloanapply :…

信息系统安全与对抗-作业2

目录 1、使用自己姓名拼音创建一个账户&#xff0c; 并使用命令和图形化查看 2、使用自己拼音打头字母创建一个隐藏账户 &#xff0c;并使用命令和图形化查看 3、使用命令启动 telnet 服务 4、使用命令打开防火墙 23 端口 5、熟悉LINUX系统&#xff0c;使用命令行创建用户…

排序(1)——直接插入排序+冒泡排序

目录 1 排序的概念及其应用 1.1 排序的概念 1.2 排序的应用 1.3 常见的排序算法 2 直接插入排序 2.1 基本思想 2.2 基本思路 2.3 代码实现 2.4 时间复杂度 3 冒泡排序&#xff08;回顾&#xff09; 3.1 思路分析 3.2 时间复杂度 4 比较 1 排序的概念及其应用 1.…

STP保护机制

1、BPDU保护: 为了保护边缘端口,因为当一个边缘端口收到一个BPDU时,会状变为非边缘端口,会参与生成树的计算,如果频繁的UP/DOWN,就使网络一直处于生成树的计算。 解决方法:在交换机的端口开启BPDU保护,当设置为BPDU保护的端口收到BPDU时,系统会将该端口变为down状态。…

网络安全: Kali Linux 使用 nmap 扫描目标主机

目录 一、实验 1.环境 2. Kali Linux (2024.1) 使用 namp 扫描目标主机 3.Kali Linux (2024.1)远程登录 Windows Server 4.Kali Linux (2024.1) 使用crunch字典工具 5.Kali Linux (2024.1)使用hydra密码工具 6.Kali Linux (2022.3) 通过SSH端口获取 Ubuntu 密码 二、问题…

蓝桥杯嵌入式2015年第六届省赛主观题解析

1 题目 2 解析 /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body********************************************************************…

STM32(11)按键产生中断

1.初始化IO引脚&#xff0c;设置模式&#xff0c;速度等 2.设置AFIO&#xff08;配置EXTI的引脚映射&#xff09;&#xff0c;记得开启时钟 3.配置EXTI的通道&#xff08;EXTI0和EXTI1&#xff09; 4.配置NVIC 4.1 中断优先级分组 4.2 配置中断 5.编写中断响应函数 在中断向量…

Vue前端的工作需求

加油&#xff0c;新时代打工人&#xff01; 需求&#xff1a; 实现带树形结构的表格&#xff0c;父数据显示新增下级&#xff0c;和父子都显示编辑。 技术&#xff1a; Vue3 Element Plus <template><div><el-table:data"tableData"style"width…