首页 > 其他分享 >设计模式之——代理模式

设计模式之——代理模式

时间:2024-09-18 21:23:46浏览次数:6  
标签:target JDK 对象 money 代理 模式 设计模式 public

代理模式

前言:

我们一般在租房子时会去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做;再比如我们打官司需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法;再比如在淘宝上面买东西,你使用支付宝平台支付,卖家请物流公司发货,在这个过程汇总支付宝、物流公司都扮演者“第三者”的角色在帮你完成物品的购买,这里的第三者我们可以将其称之为代理者,在我们实际生活中这种代理情况无处不在!

一.什么是代理模式

代理模式的设计动机是通过代理对象来访问真实对象,通过建立一个对象代理类,由代理对象控制原对象的引用,从而实现对真实对象的操作。在代理模式种,代理主要起到了一个中介的作用,用于协调与连接调用者(即客户端)和被调用者(即目标对象),在一定程度上降低了系统的耦合度,同时也保护了目标对象。但缺点是在调用者与被调用者增加了地阿里对象,可能会造成请求的处理速度变慢。

二.分类

代理模式分为三类:1.静态代理;2.动态代理;3.CGLIB代理

三.UML结构图

  • Subject:抽象角色,声明了真实对象和代理对象的共同接口;
  • Proxy:代理角色,实现了与真实对象相同的接口,所以在任何时刻都能够代理真实对象,并且代理对象内部包含了真实对象的引用,所以它可以操作真实对象,同时也可附加其他的操作,相当于对真实对象进行封装。

四.特点

优点:

  • 代理模式可以隐藏真实对象的实现细节,使客户端无需知道真实对象的工作方式和结构。
  • 通过代理类来间接访问真实类,可以在不修改真实类的情况下,对其进行扩展,优化或添加安全措施。
  • 代理模式实现起来简单,易于扩展和维护,符合面向对象设计原则中的开闭原则。

缺点:

  • 代理模式可能会引入额外的复杂性和间接性,增加程序设计和维护的难度。
  • 对象代理可能会降低系统性能,特别是在处理大数据或频繁调用的情况下,因为代理需要额外的计算和网络通信开销。

五.应用场景

  • AOP:通过定义切面,切入点和通知等,Spring AOP在运行时生成代理对象,将切面逻辑织入到目标对象的方法调用中。代理对象在方法调用前后执行附加操作,如日志记录,性能监控等。
  • 动态代理(JDK动态代理,CGLIB代理等):当Bean类实现了接口时,Spring使用JDK动态代理来为Bean生成代理对象;当Bean类没有实现接口时,Spring使用CGLIB代理来生成代理对象。

六.代码实现

1.静态代理:

静态代理是一种在代码编写期进行代理类和被代理类的关联的代理方式。具体实现是创建一个代理类,通常需要实现与被代理类相同的接口或继承被代理类。

房东接口类:Landlord1Service,

注意:静态代理实现它的真实对象只能有一个,多个的话,代理对象不能确定哪个对象需要被代理,会导致报错,JDK动态代理没这个问题

/**
 * 房东
 * @author Created by njy on 2023/5/30
 */
public interface Landlord1Service {
    /**
     * 出租
     * @param money 金额
     * @return
     */
    void rent(Integer money);
}

租客:TenantImpl

/**
 * 租客
 * @author Created by njy on 2023/5/30
 */
@Component
public class TenantImpl implements Landlord1Service {
 
    @Override
    public void rent(Integer money) {
        System.out.println("租下"+money+"元一个月的房子");
    }
}

静态代理:ProxyImpl

/**
 * 中介
 * @author Created by njy on 2023/5/30
 */
@Component
public class ProxyImpl implements Landlord1Service {
 
    /**
     * 房东有很多套房子,不想亲自出马了,于是找来了中介
     */
    @Autowired
    private Landlord1Service target;
 
    /**
     * 优点就是在不改变原来的实现类的情况下对方法实现了增强
     * 缺点是如果原来的接口新增了方法,那么这里也要对应实现新的方法
     * @param money 金额
     * @return
     */
    @Override
    public void rent(Integer money) {
        System.out.println("[静态代理]交中介费");
        target.rent(money);
        System.out.println("[静态代理]中介负责维修管理");
    }
}

测试:

/**
 * @author Created by njy on 2023/5/30
 */
@SpringBootTest
public class TestProxy {
    @Autowired
    private TenantImpl tenant;
 
    @Autowired
    private ProxyImpl proxy;
 
    //1.静态代理
    @Test
    void TestStatic(){
        tenant.rent(1000);
        System.out.println();
        proxy.rent(2000);
    }
}

使用场景:

  • 当代理对象只有一个时,可以使用静态代理。
  • 当被代理的类的接口比较稳定时,可以使用静态代理。
  • 当需要为多个被代理的类提供代理时,会导致代理类过多,不方便管理和维护,所以不建议使用静态代理。

2.JDK动态代理

JDK动态代理是一种比较常见的代理方式,他是在程序运行时动态生成代理类,也就是说我们在编写代码时并不知道具体代理的是什么类,而是在程序运行时动态生成。

房东接口类:Landlord2Service

/**
 * @author Created by njy on 2023/5/30
 */
public interface Landlord2Service {
 
    /**
     * 出租
     * @param money
     * @return
     */
    void rent(Integer money);
}

租客1:Teant1Impl

/**
 * @author Created by njy on 2023/5/30
 */
@Component
public class Teant1Impl implements Landlord2Service{
    @Override
    public void rent(Integer money) {
        System.out.println("tenant1租下"+money+"元一个月的房子");
    }
}

租客2:Teant2Impl

/**
 * @author Created by njy on 2023/5/30
 */
@Component
public class Tenant2Impl implements Landlord2Service {
    @Override
    public void rent(Integer money) {
        System.out.println("tenant2租下"+money+"元一个月的房子");
    }
}

JDK动态代理:JDKProxy

/**
 * JDK动态代理:就是把代理抽象了一下
 * @author Created by njy on 2023/5/30
 */
public class JDKProxy {
 
    private Object target;
 
    public JDKProxy(Object target){
        this.target=target;
    }
 
    /**
     * 给目标对象生成代理对象
     * @return 代理生成的对象
     */
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                //这里是要实现jdk代理InvocationHandler的接口,lambda表达式
                (proxy,method,args)->{
                    //执行对象方法
                    System.out.println("[JDK动态代理]交中介费");
                    method.invoke(target,args);
                    System.out.println("[JDK动态代理]中介负责维修管理");
                    return null;
                });
    }
}

Test:

/**
 * @author Created by njy on 2023/5/30
 */
@SpringBootTest
public class TestProxy {
    @Autowired
    private Teant1Impl teant1;
    @Autowired
    private Tenant2Impl tenant2;
    //2.JDK动态代理
    @Test
    void TestJDK(){
        Landlord2Service proxyInstance1 = (Landlord2Service) new JDKProxy(teant1).getProxyInstance();
        proxyInstance1.rent(2500);
 
        System.out.println();
        Landlord2Service proxyInstance2 = (Landlord2Service) new JDKProxy(tenant2).getProxyInstance();
        proxyInstance2.rent(2500);
    }
}

使用场景:

  • 对象必须实现一个或多个接口。
  • 代理类的代理方法不需要额外的逻辑。

3.Cglib代理

CDLIB代理是在运行时动态生成代理类的方法,它使用的库是cglib,和JDK代理相比,它不是动态的生成一个实现了接口的代理类,而是直接在内存中构建一个被代理的子类,并重写父类的方法来进行代理。

房东类:Landlord3Service

/**
 * @author Created by njy on 2023/5/30
 */
@Component
public class Landlord3Service {
    /**
     * 出租房屋
     * @param money
     * @return
     */
    public void rent(Integer money){
        System.out.println("租下"+money+"元一个月的房子");
    }
}

Cglib代理类:CglibProxy

/**
 * JDKProxy:cglib子类代理工厂
 * 1.代理的类不能为final
 * 2.目标对象的方法如果为final/static,那么就不会被拦截,也不会执行目标对象的业务方法
 * @author Created by njy on 2023/5/30
 */
public class CglibProxy implements MethodInterceptor {
 
    /**
     * 目标对象
     */
    private final 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("[Cglib代理]交中介费");
        method.invoke(target,objects);
        System.out.println("[Cglib代理]中介负责维修管理");
        return null;
    }
}

测试:

/**
 * @author Created by njy on 2023/5/30
 */
@SpringBootTest
@RequiredArgsConstructor
public class TestProxy {
    @Autowired
    private Landlord3Service landlord3Service;
    //3.Cglib代理
    @Test
    void TestCglib(){
        Landlord3Service proxyInstance = (Landlord3Service) new CglibProxy(landlord3Service).getProxyInstance();
        proxyInstance.rent(3000);
    }
}

使用场景:

  • 被代理的类没有实现接口或者无法实现接口。
  • 代理类的代理方法需要进行额外的逻辑,如事务处理等。

七.总结

  • 对于没有实现接口的类,只能使用CGLIB代理。
  • 对于实现了接口的类,可以使用JDK代理或者CGLIB代理,如果要求比较高的话,建议使用JDK代理。
  • 对于单个代理类的情况,并且被代理类实现了接口,可以使用静态代理。
  • 对于多个被代理类的情况,建议使用JDK代理或者CGLIB代理。

标签:target,JDK,对象,money,代理,模式,设计模式,public
From: https://www.cnblogs.com/chenlei210162701002/p/18419364

相关文章

  • 重庆“1361数字城市”模式,入选国家数据局案例!
    近期,国家数据局发布《国家数字经济创新发展试验区建设案例集》。其中,数字重庆“打造三级数字化城市运行和治理中心 探索城市精准治理新路径”入选。关注“智慧城市指北”公众号,回复关键字“20240911”,获取获得“数字经济创新发展试验区建设案例集”(前20个案例)资料的方式,案例......
  • docker pull 设置代理(一次设置/不需来回重启)
    背景dockerpull无法拉取,只能设置代理。而常规export对dockerpull无效,因实际docker调用的守护进程执行操作,dockerpull只负责传递消息。按照官方文档https://docs.docker.com/engine/daemon/proxy/,配置daemon.json,需要每次重启,且对容器内会有影响。既想在pull时走代理......
  • Nginx-HTTP和反向代理web服务器
    概述Nginx(enginex)是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,公开版本1.19.6发布于2020年12月15日。其将源代码以类BSD许可证的形式发布,因它的稳......
  • 活动系统开发之采用设计模式与非设计模式的区别-后台功能总结
    1、数据库ER图2、后台功能字段题目功能字段数据列表编号题目名称选项数量状态1=启用0=禁用创建时间修改时间保存题目名称选项集选项内容是否正确答案1=正确0=错误启禁用删除素材图库功能字段数据列表编号原文件名称文件类型文件大小加密后文件名文件具体路径上传类......
  • AI写作助力自媒体,传统模式将被颠覆
    AI在自媒体创作中的崛起 人工智能的不断发展正在彻底改变自媒体行业的运作方式。创作不再依赖单一的个人力量,AI技术的引入使得内容生成变得高效、快速。自媒体工作者可以依靠机器学习算法,获取丰富的知识和灵感,即使在众多竞争者中也能迅速脱颖而出。这种变化让人们重新审视写......
  • vue 配置代理 及 axios 请求封装和使用
    一.配置代理- vue.config.js const{defineConfig}=require('@vue/cli-service')module.exports=defineConfig({ transpileDependencies:true, //配置代理服务器 devServer:{  proxy:{   '/baidu':{    target:'https://ba......
  • spring工厂模式
    https://blog.csdn.net/qq_57005976/article/details/134367016工厂模式工厂模式的三种形态:工厂模式是解决对象创建问题的属于创建型设计模式,Spring框架底层使用了大量的工厂模式第一种:简单工厂模式是工厂方法模式的一种特殊实现,简单工厂模式又叫静态工厂方法模式不属于23种......
  • CMS32L051驱动WS2812B全彩灯-PWM+DMA模式
    文章目录概要代码小结概要基于中微CMS32L051驱动WS2812B全彩灯,使用PWM+DMA模式。参照中微的串口uartSendReceive,该例程中有使用DMA进行串口数据的收发。代码main.c/******************************************************************************************......
  • 设计模式——代理模式
    设计模式——代理模式1.代理模式(Proxy)1.1代理模式的基本介绍代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。被代理的对象可以是远程对象、......
  • Qt 模型视图(四):代理类QAbstractItemDelegate
    文章目录Qt模型视图(四):代理类`QAbstractItemDelegate`1.基本概念1.1.使用现有代理1.2.一个简单的代理2.提供编辑器3.向模型提交数据4.更新编辑器的几何图形5.编辑提示Qt模型视图(四):代理类QAbstractItemDelegate​模型/视图结构是一种将数据存储和界面展示分......