从零开始学设计模式(七):代理模式(Proxy Pattern)

简介: 代理模式可以说是在日常开发中听到用到最多的设计模式之一了。

定义


代理模式可以说是在日常开发中听到用到最多的设计模式之一了。


代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。它是一种对象结构型模式。


所以可以这样理解:比如你要租房子,你不能直接与房东进行访问和他进行交谈,这时候你就需要一个房屋中介,你把你的需求告诉他,房东把他的需求也告诉他,这时候他负责作为中间的传话筒传递你们的意思,间接的提供了你对于房东的一个访问!


组成部分


通过对于代理模式的定义和描述可以发现它应该有三个关键的角色:你、房东、房屋中介。即:


抽象角色Subject:声明真实对象和代理对象的共同接口。房东。


代理角色Proxy:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。房屋中介。


真实角色RealSubject:代理角色所代表的真实对象,是我们最终要引用的对象。你。


代理模式的分类


我们经常听到一个词:动态代理,既然有动态代理,与之对应肯定有静态代理。所以代理模式主要分为动态和静态代理两种设计模式。接下来分别介绍下:


静态代理


静态代理指得是由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。


静态代理的例子:


抽象角色,真实对象和代理对象共同的接口 这里是房东的角色:


package com.jiangxia.ProxyPattern.jingtaiProxy;
/**
 * @Author: 江夏
 * @Date: 2021/10/31/10:07
 * @Description:抽象对象:房东 提供 签约 看房的功能
 */
public interface FangDong {
        //签约功能
        public void sign ();
        //看房功能
        public void lookHouse ();
}
复制代码


代理角色需要实现抽象角色的方法,这里是中介的角色:


package com.jiangxia.ProxyPattern.jingtaiProxy;
/**
 * @Author: 江夏
 * @Date: 2021/10/31/10:10
 * @Description:
 */
public class ZhongJie implements FangDong{
    public FangDong fangDong;
    public ZhongJie(FangDong fangDong) {
        this.fangDong = fangDong;
    }
    @Override
    public void sign() {
        System.out.println("中介替房东答应与你签约");
    }
    @Override
    public void lookHouse() {
        System.out.println("中介替房东带你去看房");
    }
}
复制代码


真实角色,你:


package com.jiangxia.ProxyPattern.jingtaiProxy;
/**
 * @Author: 江夏
 * @Date: 2021/10/31/10:13
 * @Description:
 */
public class FangKe implements FangDong{
    @Override
    public void sign() {
        System.out.println("你签合同了!");
    }
    @Override
    public void lookHouse() {
        System.out.println("你去看房了!");
    }
}
复制代码


测试代码:


/**
 * @Author: 江夏
 * @Date: 2021/10/31/10:15
 * @Description:
 */
public class Test {
    public static void main(String[] args) {
        FangDong fangke = new FangKe();
        FangDong zhongjie = new ZhongJie(new FangKe());
        zhongjie.lookHouse();
        zhongjie.sign();
    }
}
复制代码


输出结果如下:

7df0d60e59f74e4897f6763a36229ecb~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


动态代理


与静态代理不同的是动态代理类的源码是程序在运行期间由JVM根据反射等机制动态生成的,所以不存在代理类的字节码文件。代理角色和真实角色的联系在程序运行时确定。


动态代理是一种较为高级的代理模式,它的典型应用就是Spring AOP。


动态代理的例子:


抽象角色和真实角色即房东和房客代码和上面一样。主要区别是代理角色的处理以及方法的调用:


代理代码如下:


package com.jiangxia.ProxyPattern.Dongtai;
import com.jiangxia.ProxyPattern.jingtaiProxy.FangDong;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class proxyHandler  implements InvocationHandler {
         private FangDong userImpl;
         public proxyHandler(FangDong userImpl){
             this.userImpl= userImpl;
         }
         @Override
         public Object invoke(Object proxy, Method method, Object[] args)
                                        throws Throwable {
                   Object object = null;
       //方法开始前做一些事情
       if (method.getName().equals("sign")) {
           //激活调用的方法
           object = method.invoke(userImpl, args);
       }
       //方法结束后做一些事情
       return object;
    }
}
复制代码


测试代码:


package com.jiangxia.ProxyPattern.Dongtai;
import com.jiangxia.ProxyPattern.jingtaiProxy.FangDong;
import com.jiangxia.ProxyPattern.jingtaiProxy.FangKe;
import java.lang.reflect.Proxy;
public class Test {
   public static void main(String[] args) {
         FangDong fangek =new FangKe();
         proxyHandler handler = new proxyHandler(fangek);
         FangDong zhongjie = (FangDong)Proxy.newProxyInstance
                      (ClassLoader.getSystemClassLoader(), new Class[]{FangDong.class}, handler);
         zhongjie.sign();
   }
}
复制代码


运行结果:

fc803c9ee29940eebd329405237a2121~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


代理模式优点


1、业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。


2、能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。


3、虚拟代理通过使用一个小对象来代表一个大对象,可以减少系 统资源的消耗,对系统进行优化并提高运行速度。


4、保护代理可以控制对真实对象的使用权限。


5、远程代理使得客户端可以访问在远程机器上的对象,远程机器 可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。


代理模式缺点


1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理。


2、实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂,例如远程代理。


应用场景


当无法或不想直接引用某个对象或访问某个对象存在困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。


前面分析了代理模式的结构与特点,现在来分析以下的应用场景。


1、远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。


2、虚拟代理,这种方式通常用于要创建的目标对象开销很大时。例如,下载一幅很大的图像需要很长时间,因某种计算比较复杂而短时间无法完成,这时可以先用小比例的虚拟代理替换真实的对象,消除用户对服务器慢的感觉。


3、安全代理,这种方式通常用于控制不同种类客户对真实对象的访问权限。


4、智能指引,主要用于调用目标对象时,代理附加一些额外的处理功能。例如,增加计算真实对象的引用次数的功能,这样当该对象没有被引用时,就可以自动释放它。


5、延迟加载,指为了提高系统的性能,延迟对目标的加载。例如,Hibernate 中就存在属性的延迟加载和关联表的延时加载。


6、Spring中的AOP使用的就是动态代理


目录
相关文章
|
3月前
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
3月前
|
设计模式 Java 数据安全/隐私保护
Java设计模式-代理模式(7)
Java设计模式-代理模式(7)
|
3月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
3月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
4月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
4月前
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
|
5月前
|
设计模式 算法 Go
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
|
5月前
|
设计模式 缓存 JavaScript
js设计模式【详解】—— 代理模式
js设计模式【详解】—— 代理模式
33 0
|
6月前
|
设计模式 监控 安全
设计模式之代理模式(Java)
设计模式之代理模式(Java)
|
28天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式