代理模式

简介: 代理模式

代理模式


代理模式是很常见的一种设计模式,代理一词拆开来看就是代为受理,那显然是要涉及到请求被代理的委托方,提供代理的代理方,以及想要通过代理来实际联系委托方的客户三个角色。举个生活中常见的例子,房东都是通过中介来处置自己的房屋,并不与租客直接接触,这种场景下,房东本身是委托方,中介是代理方,房东把自己的房屋委托给中介进行房屋出租,这样当租客想要租房的时候,只能通过中介来咨询办理。这样房东自身不用暴露身份,不用和租客费时沟通,带领租客看房等一系列问题,这样都转由中介来解决。当然,中介也可以给多个房东提供服务,这样租客只接触一个中介,就可以看到不同的房源,最终找到符合心意的房间。


通过上面的例子,代理模式有以下两个优点:

  1. 可以隐藏委托类的实现;
  2. 可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。


字节码处理


Java 程序员都应该知道,Java 通过 Javac 编译器将.java 源文件编译成能被 JVM 虚拟机识别的.class 字节码文件, 当 .class字节码文件通过 JVM 转为机器可以执行的二进制机器码时,JVM 类加载器首先加载字节码文件,然后通过解释器逐行进行解释执行 ,生成对应的 Class 对象,进而使 Class 对象创建类的具体实例来进行调用实现具体的功能。


image.png


上图说明了 Java 加载字节码的流程,但是 Java 的强大在于不仅仅可以加载在编译器生成好的字节码,还可以在运行期系统中,遵循 Java 编译系统组织.class 文件的格式和结构,生成相应的二进制数据,然后再把这个二进制数据加载转换成对应的类,这样就完成了在代码动态创建一个类的能力,如下图流程。


image.png


关于动态生成类的技术目前有两种,一种是自己动手,从零开始创建字节码,理论上可行,实际上很难;第二种是,使用已有的一些能操作字节码的库,帮助我们创建 class。目前,能够操作字节码的常用的工具/库有:



Javassist 是一个开源的分析、编辑和创建 Java 字节码的类库, 接下来我们使用 Javasisst 工具在运行时动态创建字节码并加载类,如下代码:


package com.msdn.classLoad;
public class JavasisstLearn {
    /**
     * 动态生成一个新类
     * @return
     */
    public static Class<?> createNewClass(){
        try {
            //获取ClassPool
            ClassPool pool = ClassPool.getDefault();
            //创建User类
            CtClass ctClass = pool.makeClass("com.msdn.bean.User");
            //创建User类成员变量name
            CtField name = new CtField(pool.get("java.lang.String"),"name",ctClass);
            //设置name为私有
            name.setModifiers(Modifier.PRIVATE);
            //将name写入class,并初始化为空
            ctClass.addField(name,CtField.Initializer.constant(""));
            //增加set方法,名字为“setName”
            ctClass.addMethod(CtNewMethod.setter("setName",name));
            //增加get方法,名称为“getName”
            ctClass.addMethod(CtNewMethod.getter("getName",name));
            //添加无参构造函数
            CtConstructor constructor = new CtConstructor(new CtClass[] {},ctClass);
            constructor.setBody("{name = \"hresh\";}");//相当于public Sclass(){this.name = "hresh";}
            ctClass.addConstructor(constructor);
            //添加有参构造函数
            constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String")},ctClass);
            constructor.setBody("{$0.name = $1;}");//第一个传入的形参$1,第二个传入的形参$2,相当于public Sclass(String s){this.name = s;}
            ctClass.addConstructor(constructor);
            System.out.println(ctClass.getDeclaredField("name"));
            //反射调用新创建的类
            Class<?> uClass = ctClass.toClass();
            Object user = uClass.newInstance();
            Method getter = null;
            getter = user.getClass().getMethod("getName");
            System.out.println(getter.invoke(user));
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        createNewClass();
    }
}
复制代码


这里只是介绍了 Javasisst 工具的部分功能,感兴趣的朋友可以参考这两篇文章:Java动态编程初探——JavassistJavassist中文技术文档


在 Java 学习的过程中,我们多是默认使用静态加载字节码,对于动态加载字节码没有过多接触,但是在某些技术场景下显得尤为必要。关于动态生成类的场景的介绍大家可以参考 Java动态生成类的场景的考察


介绍静态和动态加载字节码的两种方式,是为了引出下面关于两种代理方式的介绍,代理机制通过代理类创建时间的不同分为了静态代理和动态代理:


  • 静态代理:代理类在编译阶段生成,程序运行前就已经存在,那么这种代理方式被称为静态代理,这种情况下的代理类通常都是我们在 Java 代码中定义的。
  • 动态代理:代理类在程序运行时创建,也就是说,这种情况下,代理类并不是在 Java 代码中定义的,而是在运行时根据我们在 Java 代码中的“提示”动态生成的。


目前,静态代理主要有 AspectJ 静态代理、JDK 静态代理技术 ,而动态 代理有 JDK 动态代理、Cglib 动态代理技术,而 Spring AOP 是整合使用了 JDK 动态代理和 Cglib 动态代理两种技术。


关于 Java 编程的动态性有一系列的文章,有兴趣的朋友可以去阅读一番:Java动态化


静态代理


AspectJ 静态代理


关于 AspectJ 在 IDEA 中的配置,以及简单的案例学习,可以参看AspectJ入门及在IDEA中的配置一文。


将租房抽象为一个 Rent 接口,如下:


public interface Rent {
    public void rent();
}
复制代码


房东实现了 Rent 接口:


public class Host implements Rent {
    public void rent() {
        System.out.println("房屋出租");
    }
}
复制代码


用 AspectJ 语法实现一个代理 IntermediaryAspectJ:


public aspect IntermediaryAspectJ {
    //定义切点
    pointcut rentPointCut():call(void com.msdn.bean.Host.rent());
    /**
     * 定义前置通知
     * befor(参数):连接点函数{
     *     函数体
     * }
     */
    before():rentPointCut(){
        seeHouse();
    }
    /**
     * 定义后置通知
     * after(参数):连接点函数{
     *     函数体
     * }
     */
    after():rentPointCut(){
        fare();
    }
    private void seeHouse(){
        System.out.println("带租客看房");
    }
    private void fare(){
        System.out.println("收中介费");
    }
}
复制代码


测试代码如下:


public class AspectJTest {
    public static void main(String[] args) {
        Host host = new Host();
        host.rent();
    }
}
复制代码


执行结果为:


带租客看房
房屋出租
收中介费
复制代码


可以看到 Host 的 rent()方法前后输出了我们在 IntermediaryAspectJ 中定义的前置和后置通知,该类充当代理的功能。具体的 AspectJ 语法我们不深究,只需要知道 pointcut 是定义要代理的切入点,这里是定义了一个 pointcut,代理 Host 类中的 rent()方法。而  before()和 after()分别可以定义具体在切入点前后需要的额外操作。


总结一下,AspctJ 就是用特定的编译器和语法,对类实现编译期增强,实现静态代理技术,下面我们看 JDK 静态代理。


JDK静态代理


JDK 静态代理更多的是一种设计模式,JDK 静态代理的代理类和委托类会实现同一接口或是派生自相同的父类,代理类对客户对象是可见的,其结果图如下:


image.png


继续套用上面租房的例子,改写代码实现一个 JDK 静态代理模式。


中介也实现 Rent 接口,持有一个房东对象来提供租房服务,包括带领租客看房,解答相关疑问等:


public class Intermediary implements Rent {
    private Host host;
    public Intermediary() {
    }
    public Intermediary(Host host) {
        this.host = host;
    }
    @Override
    public void rent() {
        seeHouse();
        host.rent();
        fare();
    }
    public void seeHouse(){
        System.out.println("带租客看房");
    }
    public void fare(){
        System.out.println("收中介费");
    }
}
复制代码


通过中介来替房东完成租房行为:


public class JdkTest {
    public static void main(String[] args) {
        Host host = new Host();
        Intermediary proxy = new Intermediary(host);
        proxy.rent();
    }
}
复制代码


执行结果同上。


以上就是一个典型的静态代理的实例,很简单但是也能说明问题,我们可以分析一下静态代理的优缺点:


优点:静态代理在编译时产生 class 文件,运行时无需产生,可直接使用,效率好。业务类可以只关注自身逻辑,可以重用,通过代理类来增加通用的逻辑处理;


缺点:静态代理要为每个目标类创建一个代理类,当需要代理的对象太多,那么代理类也变得很多。同时代理类违背了可重复代理只写一次的原则。 另外当接口中增加方法时,所有实现类都需要实现该方法,增加代码维护的复杂度。


关于静态代理存在的缺陷,可以通过动态代理来解决。


动态代理


动态代理中,代理类并不是在 Java 代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等,动态代理分为 JDK动态代理和 cglib 动态代理。

JDK动态代理


JDK 提供了动态代理,其原理图如下:


image.png


还以中介和房东的模型为例,将租房抽象为一个接口:


public interface Rent {
    public void rent();
}
复制代码


房东实现了 Rent 接口:


public class Host implements Rent {
    public void rent() {
        System.out.println("房屋出租");
    }
}
复制代码


实现一个代理类的请求处理器,处理对具体类的所有方法的调用:


public class InvocationHandlerImpl implements InvocationHandler {
    Rent rent;
    public InvocationHandlerImpl(Rent rent) {
        this.rent = rent;
    }
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        seeHouse();
        //租房
        Object object = method.invoke(rent,objects);
        fare();
        return object;
    }
    public void seeHouse(){
        System.out.println("带租客看房");
    }
    public void fare(){
        System.out.println("收中介费");
    }
}
复制代码


通过 JDK 动态代理机制实现一个动态代理:


public class JdkProxy {
    public static void main(String[] args) {
        //创建被代理的具体类
        Host host = new Host();
        //获取对应的ClassLoader
        ClassLoader classLoader = host.getClass().getClassLoader();
        //获取被代理对象实现的所有接口
        Class[] interfaces = host.getClass().getInterfaces();
        //设置请求处理器,处理所有方法调用
        InvocationHandler invocationHandler = new InvocationHandlerImpl(host);
        /**
         * 5.根据上面提供的信息,创建代理对象 在这个过程中,
         *   a.JDK会通过根据传入的参数信息动态地在内存中创建和.class文件等同的字节码
         *   b.然后根据相应的字节码转换成对应的class,
         *   c.然后调用newInstance()创建实例
         */
        Object o = Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
        Rent rent = (Rent) o;
        rent.rent();
    }
}
复制代码


我们从代理的创建入手,看看 JDK 的动态代理都做了什么。 在 Jdk 的 java.lang.reflect 包下有个 Proxy 类,它正是构造代理类的入口。这个类的结构入下:


image.png


从上图发现最后面四个是公有方法。而最后一个方法 newProxyInstance 就是创建代理对象的方法。这个方法的源码如下:


public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2) throws IllegalArgumentException {
        Objects.requireNonNull(var2);
        Class[] var3 = (Class[])var1.clone();
        SecurityManager var4 = System.getSecurityManager();
        if (var4 != null) {
            checkProxyAccess(Reflection.getCallerClass(), var0, var3);
        }
        Class var5 = getProxyClass0(var0, var3);
        try {
            if (var4 != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), var5);
            }
            final Constructor var6 = var5.getConstructor(constructorParams);
            if (!Modifier.isPublic(var5.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        var6.setAccessible(true);
                        return null;
                    }
                });
            }
            return var6.newInstance(var2);
        } catch (InstantiationException | IllegalAccessException var8) {
            throw new InternalError(var8.toString(), var8);
        } catch (InvocationTargetException var9) {
            Throwable var7 = var9.getCause();
            if (var7 instanceof RuntimeException) {
                throw (RuntimeException)var7;
            } else {
                throw new InternalError(var7.toString(), var7);
            }
        } catch (NoSuchMethodException var10) {
            throw new InternalError(var10.toString(), var10);
        }
    }
复制代码


这个方法需要三个参数:ClassLoader,用于加载代理类的 Loader 类,通常这个 Loader 和被代理的类是同一个 Loader 类。Interfaces,是要被代理的那些那些接口。


InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,它也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。


下面还是看看 Proxy 如何产生代理类的过程,它构造出来的代理类到底是什么样子?下面揭晓啦。  


image.png


具体步骤如下:


  1. Proxy.newProxyInstance()获取 Host 类的所有接口列表(第二个参数:interfaces);
  2. 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX;
  3. 根据需要实现的接口信息,在代码中动态创建该 Proxy 类的字节码;
  4. 将对应的字节码转换为对应的 class 对象;
  5. 创建 InvocationHandler 实例 handler,用来处理 Proxy 所有方法调用;
  6. Proxy 的 class 对象以创建的 handler 对象为参数(第三个参数: invocationHandler ),实例化一个 Proxy 对象。


而对于 InvocationHandler,我们需要重写其 invoke 方法:


public Object invoke(Object proxy, Method method, Object[] args) 
复制代码


在调用代理对象中的每一个方法时,在代码内部,都是直接调用了 InvocationHandler  的 invoke 方法,而 invoke 方法根据代理类传递给自己的 method 参数来区分是什么方法。


可以看出,Proxy.newProxyInstance() 方法生成的对象也是实现了 Rent 接口的,所以可以在代码中将其强制转换为 Rent 来使用,和静态代理达到了同样的效果。我们可以用下面代码把生成的代理类的字节码保存到磁盘里,然后反编译看看 JDK 生成的动态代理类的结构。


public class ProxyUtils {
    public static void main(String[] args) {
        Host host = new Host();
        genereateClassFile(host.getClass(),"HostProxy");
    }
    public static void genereateClassFile(Class clazz,String proxyName){
        //根据类信息和提供的代理类名称,生成字节码
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName,clazz.getInterfaces());
        String paths = clazz.getResource(".").getPath();
        System.out.println(paths);
        FileOutputStream out = null;
        try {
            //保存到硬盘中
            out = new FileOutputStream(paths + proxyName + ".class");
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
复制代码


编译后的 HostProrxy.class 文件结果如下:


//动态代理类HostProrxy实现了Rent接口
public final class HostProxy extends Proxy implements Rent {
    //加载接口中定义的所有方法
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;
    //构造函数接入InvocationHandler,也就是持有了InvocationHandler对象
    public HostProxy(InvocationHandler var1) throws  {
        super(var1);
    }
    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    //自动生成的rent方法,实际调用InvocationHandler对象的invoke方法,传入m3参数对象代表rent()方法
    public final void rent() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    //加载接口中定义的所有方法
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.msdn.bean.Rent").getMethod("rent");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
复制代码


通过查看编译后的代码可以看出,JDK 生成的动态代理类实现和具体类相同的接口,并持有 InvocationHandler 对象(InvocationHandler对象又持有具体类),调用动态代理类中的方法,会触发传入 InvocationHandler 的 invoke()方法 ,通过  method 参数,来区分调用的是什么具体的方法。


注意:JDK 动态代理会根据被代理对象生成一个继承了 Proxy 类,并实现了该业务接口的 JDK 代理类,该类的字节码会被传进去的 ClassLoader 加载,创建了 JDK 代理对象实例。


JDK 代理对象实例创建时,业务代理对象实例会被赋值给 Proxy 类,JDK 代理对象实例也就有了业务代理对象实例,同时 JDK 代理对象实例通过反射根据被代理类的业务方法创建了相应的 Method 对象m(可能有多个)。当 JDK 代理对象实例调用业务方法,如 proxy.rent();此时会先把对应的m对象作为参数传给 invoke()方法(就是 invoke 方法的第二个参数),调用了 JDK 代理对象实例的 invoke()回调方法,在 invoke 方法里面再通过反射调用被代理对象的方法,即 Object object = method.invoke(rent,objects);


CGLIB动态代理


JDK 中提供的生成动态代理类的机制有个鲜明的特点是:

某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法,比如:如果上述例子的 Host 类实现了继承自 Rent 接口的方法外,自身另外实现了方法 buyHouse(),则在产生的动态代理类中不会有这个方法。更极端的情况是:如果某个类没有实现接口,那么这个类就不能用 JDK 产生动态代理。


那么怎么解决上述存在的问题呢?这里介绍一种新的代理方法——CGLIB,“CGLIB(Code Generation Library),是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展 Java 类与实现J ava接口。


CGLIB 创建某个类A的动态代理类的模式是:


  1. 查找A上的所有非 final 的 public 类型的方法定义;
  2. 将上述步骤中的方法的定义转换成字节码;
  3. 将组成的字节码转换成相应的代理的 Class 对象;
  4. 实现 MethodInterceptor 接口,用来处理对代理类上的所有方法的请求(该接口和 JDK 动态代理 InvocationHandler 的功能和角色是一样的)


有了上述 JDK 动态代理的例子,CGLIB 就比较容易理解了,接下里用案例进行分析,复用上述的 Rent 接口和 Host 类。


Maven 导入 CGLIB 相关包,格式如下:


<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.6</version>
</dependency>
复制代码


实现 MethodInterceptor 接口:


public class MethodInterceptorImpl implements MethodInterceptor {
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        seeHouse();
        Object object = methodProxy.invokeSuper(o,objects);
        fare();
        return object;
    }
    public void seeHouse(){
        System.out.println("带租客看房");
    }
    public void fare(){
        System.out.println("收中介费");
    }
}
复制代码


创建动态代理:


public class CglibProxyDemo {
    public static void main(String[] args) {
        Host host = new Host();
        MethodInterceptor methodInterceptor = new MethodInterceptorImpl();
        //cglib中加强器,用来创建动态代理
        Enhancer enhancer = new Enhancer();
        //设置要创建动态代理的类
        enhancer.setSuperclass(host.getClass());
        //设置回调,这里相当于是对于代理类上所有方法的调用,都会调用Callback,而Callback则需要实行intercept()方法进行拦截
        enhancer.setCallback(methodInterceptor);
        Rent rent = (Rent) enhancer.create();
        rent.rent();
    }
}
复制代码


通过以上实例可以看出,Cglib 通过继承实现动态代理,具体类不需要实现特定的接口,而且代理类可以调用具体类的非接口方法,更加灵活。


关于 JDK 动态代理和 CGLIB动态代理适用范围的不同,需要修改一下 Host 类,然后查看动态代理执行的结果。


Host.java


public class Host implements Rent {
    public void rent() {
        System.out.println("房屋出租");
    }
    public void buyHouse(){
        System.out.println("买房后续出租");
    }
    public final void travel(){
        System.out.println("旅游!!!");
    }
}
复制代码


JdkProxy.java


public class JdkProxy {
    public static void main(String[] args) {
        //创建被代理的具体类
        Host host = new Host();
        //获取对应的ClassLoader
        ClassLoader classLoader = host.getClass().getClassLoader();
        //获取被代理对象实现的所有接口
        Class[] interfaces = host.getClass().getInterfaces();
        //设置请求处理器,处理所有方法调用
        InvocationHandler invocationHandler = new InvocationHandlerImpl(host);
        /**
         * 5.根据上面提供的信息,创建代理对象 在这个过程中,
         *   a.JDK会通过根据传入的参数信息动态地在内存中创建和.class文件等同的字节码
         *   b.然后根据相应的字节码转换成对应的class,
         *   c.然后调用newInstance()创建实例
         */
        Object o = Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
        Rent rent = (Rent) o;
//        Rent rent = (Rent) new InvocationHandlerImpl().newInstance(host);
        rent.rent();
        Host host1 = (Host) o;
        host1.buyHouse();
        host1.travel();
    }
}
复制代码


执行结果为:


带租客看房
房屋出租
收中介费
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.msdn.bean.Host
    at com.msdn.dynamic.JdkProxy.main(JdkProxy.java:36)
复制代码


CglibProxyDemo.java


public class CglibProxyDemo {
    public static void main(String[] args) {
        Host host = new Host();
        MethodInterceptor methodInterceptor = new MethodInterceptorImpl();
        //cglib中加强器,用来创建动态代理
        Enhancer enhancer = new Enhancer();
        //设置要创建动态代理的类
        enhancer.setSuperclass(host.getClass());
        //设置回调,这里相当于是对于代理类上所有方法的调用,都会调用Callback,而Callback则需要实行intercept()方法进行拦截
        enhancer.setCallback(methodInterceptor);
        Rent rent = (Rent) enhancer.create();
        rent.rent();
        Host host1 = (Host) enhancer.create();
        host1.buyHouse();
        host1.travel();
    }
}
复制代码


执行结果为:


带租客看房
房屋出租
收中介费
带租客看房
买房后续出租
收中介费
旅游!!!
复制代码


总结:JDK 动态代理必须实现接口,通过反射来动态生成代理方法,消耗系统性能。Cglib 动态代理无需实现接口,通过生成子类字节码来实现,比反射快一点,没有性能问题。但是由于 Cglib 会继承被代理类,需要重写被代理方法,所以被代理类不能是 final 类,被代理方法不能是 final 标识。因此,Cglib 应用更加广泛一些。


目录
相关文章
|
5月前
|
设计模式
对于装饰器模式与代理模式的个人理解
摘要: 代理模式与装饰器模式虽相似,但目的不同。装饰器动态增强对象功能,如添加新特性,而不改变原有类。代理模式则用于控制访问,如优化昂贵操作或添加辅助服务(如日志),它可能在内部初始化原对象。用法上,装饰器由外部决定是否应用,允许链式创建,而代理通常内部调用,外部直接与代理交互,被代理对象可能独立不可用。
|
7月前
|
缓存 数据安全/隐私保护 C++
【C++】—— 代理模式
【C++】—— 代理模式
代理模式——为他人做嫁衣裳
代理模式——为他人做嫁衣裳
|
7月前
|
设计模式 Java
代理模式与动态代理
代理模式与动态代理
48 0
|
7月前
|
Java Spring
代理模式
代理模式
58 0
|
Java 网络安全 Maven
代理模式的运用
代理模式的运用
67 0
|
设计模式 JavaScript
关于代理模式我所知道的
关于代理模式我所知道的
89 0
|
Java Spring
代理模式你了解多少
代理模式你了解多少
84 0
|
设计模式 缓存 监控
我学会了,代理模式
代理模式属于结构型模式,这个类型的设计模式总结出了 类、对象组合后的经典结构,将类、对象的结构和使用解耦了,花式的去借用对象。
101 0
我学会了,代理模式
|
存储 设计模式 缓存
万洋-什么是代理模式
简介: 影视导演找演员谈合作一般是不会直接找到演员本人,而是先找到演员的经纪人,先由经纪人洽谈,经纪人觉得合适的话就会与演员本人商讨合作事项,这个过程导演与演员是不直接接触的。 这里就用到了**代理模式**,导演其实想找的人是演员,但是要先找到是经纪人,再由经纪人找演员沟通。真正的价值在于演员,但是这个过程中,对于导演来说,经纪人与演员体现出了同样的价值,经纪人会全权代理演员与导演洽谈,经纪人会用自己的专业性过滤掉一些不好的合作意向,从而避免演员被频繁打扰。
130 0
万洋-什么是代理模式