设计模式之代理模式

22 篇文章 0 订阅

概述

1、代理模式简介

代理模式是客户端不直接调用实际对象,而是通过调用代理对象来间接调用使用实际对象。
在这里插入图片描述在代理模式中有如下角色:

  • ISubject: 抽象主题类,声明真实主题与代理的共同接口方法。
  • RealSubject:真实主题类,代理类所代表的真实主题。客户端通过代理类间接地调用真实主题类的方法。
  • Proxy:代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行。
2、为啥使用代理模式:
  • 中间隔离:某些情况下,客户端不想或者不能直接引用一个目标对象,而代理类可以在客户端和目标类之前起到中介作用
  • 开闭原则,扩展功能:代理类除了是客户类和目标类的中介,还可以通过给代理类增加额外的功能来扩展目标类的功能,这样我们只需要修改代理类而不需要再修改目标类,
  • 符合代码设计的开闭原则(对扩展开放,对修改关闭)。代理类主要负责为目标类预处理消息、过滤消息、把消息转发给目标类,以及事后对返回结果的处理等。
  • 代理类本身并不真正实现服务,而是同过调用目标类的相关方法,来提供特定的服务。真正的业务功能还是由目标类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的目标类。
3、代理实现方式:

按照代理创建的时期来进行分类的话, 可以分为静态代理、动态代理

  • 静态代理是由程序员创建或特定工具自动生成代理类,再对其编译,在程序运行之前,代理类.class文件就已经被创建了
  • 动态代理是在程序运行时通过反射机制动态创建代理对象
4、如何区分静态代理和动态代理?

静态代理:程序运行前,代理类已经存在。
动态代理:程序运行前,代理类不存在,运行过程中,动态生成代理类。

静态代理

(一)抽象接口
public interface ILawsuit {
    void submit();//提交申请
    void burden();//进行举证
    void defend();//开始辩护
    void finish();//诉讼完成
}
(二)真实实现类
public class XiaoMin implements ILawsuit {
    @Override
    public void submit() {
        System.out.println("submit");
    }

    @Override
    public void burden() {
        System.out.println("burden");
    }

    @Override
    public void defend() {
        System.out.println("defend");
    }

    @Override
    public void finish() {
        System.out.println("finish");
    }
}
(三)代理类
public class Layer implements ILawsuit {

    private ILawsuit mLawsuit;

    public Layer(ILawsuit lawsuit) {
        this.mLawsuit = lawsuit;
    }

    @Override
    public void submit() {
        mLawsuit.submit();
    }

    @Override
    public void burden() {
        mLawsuit.burden();
    }

    @Override
    public void defend() {
        mLawsuit.defend();
    }

    @Override
    public void finish() {
        mLawsuit.finish();
    }
}
(四)代理使用过程
public class Main {
    public static void main(String[] args) {

        ILawsuit xiaomin = new XiaoMin();
        
        ILawsuit layer = new Layer(xiaomin);
        
        layer.submit();
        layer.burden();
        layer.defend();
        layer.finish();
    }
}

通过上面的代码我们可以看出静态代理的优缺点

  • 优点:代理类可以接受一个已经实现了Subject接口的对象,任何实现了Subject接口的对象都可以通过代理类进行代理,实现了通用型
  • 缺点:当接口增删改方法,那么代理类已得要跟着修改;代理类的每个接口对象对应一个委托对象,如果委托对象很多,代理类就会变得异常臃肿

动态代理

程序运行前,代理类不存在,运行过程中,动态生成代理类。
在这里插入图片描述

1、为什么要使用动态代理?
  • 因为一个静态代理类只能服务一种类型的目标对象,在目标对象较多的情况下,会出现代理类较多、代码量较大的问题。而使用动态代理动态生成代理者对象能避免这种情况的发生。

  • 优点:相对于静态代理,极大的减少类的数量,降低工作量,减少对业务接口的依赖,降低耦合,便于后期维护;同时在某些情况下是最大的优势,即可以统一修改代理类的方法逻辑,而不需要像静态代理需要修改每个代理类

  • 缺点:因为使用的是反射,所以在运行时会消耗一定的性能;同时动态代理只支持interface的动态代理,如果你再继续深究源码,会发现,所有动态生成的代理对象都有一个共同的父类,即都继承于Proxy;Java的单继承机制决定了无法支持class的动态代理,也就意味着你拿到动态生成的代理对象,只能调用其实现的接口里的方法,无法像静态代理中的代理类可以在内部扩展更多的功能.

2、动态代理使用
  • (1)定义抽象接口:
public interface ILawsuit {
    void submit();//提交申请
    void burden();//进行举证
    void defend();//开始辩护
    void finish();//诉讼完成
}

  • (2)真实接口实现类:
public class XiaoMin implements ILawsuit {
    @Override
    public void submit() {
        System.out.println("submit");
    }

    @Override
    public void burden() {
        System.out.println("burden");
    }

    @Override
    public void defend() {
        System.out.println("defend");
    }

    @Override
    public void finish() {
        System.out.println("finish");
    }
}

  • (3)动态代理类方法调用处理程序:
public class DynamicProxy implements InvocationHandler {

    private Object obj;
    public DynamicProxy(Object obj){
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(obj,args);
        return result;
    }
}
  • (4)使用动态代理:
/**
 * JDK动态代理生成的class文件保存到本地失败问题(sun.misc.ProxyGenerator.saveGeneratedFiles)
 *
 *  1、将JDK动态代理生成的class文件保存到本地,网上搜到的办法是加入:
 *
 *     System.getProperties().put(""sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
 *
 *     发现实际并未生效,先给答案,新版本JDK改为:
 *
 *   System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
 *
 *   如果不确定,可以在IDEA双击shift,输入ProxyGenerator,发现只有java.lang.reflect中存在该类,其中:
 *   private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("jdk.proxy.ProxyGenerator.saveGeneratedFiles"));
 */
public class MainV2 {
    public static void main(String[] args) {
// 在工程目录下生成 $Proxy0 的 class 文件     
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

        // 动态代理
        ILawsuit xiaomin = new XiaoMin();

        DynamicProxy dynamicProxy = new DynamicProxy(xiaomin);

        ClassLoader classLoader = xiaomin.getClass().getClassLoader();

        ILawsuit layer = (ILawsuit) Proxy.newProxyInstance(classLoader,new Class[]{ILawsuit.class},dynamicProxy);

        layer.submit();
        layer.burden();
        layer.defend();
        layer.finish();

        System.out.println("$Proxy0.class全名: "+Proxy.getProxyClass(classLoader,ILawsuit.class));

        System.out.println("目标对象2:" + xiaomin.getClass());
        System.out.println("代理对象2:" + layer.getClass());
    }


}
  • (5)输出结果
"D:\IntelliJ IDEA 2019.3.1\jbr\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2019.3.1\lib\idea_rt.jar=52562:D:\IntelliJ IDEA 2019.3.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IdeaProject\ProxyPattern\out\production\ProxyPattern dynamicProxy.MainV2
submit
burden
defend
finish
$Proxy0.class全名: class com.sun.proxy.$Proxy0
目标对象2class dynamicProxy.XiaoMin
代理对象2class com.sun.proxy.$Proxy0

从日志中可以看到代理类是 com.sun.proxy.$Proxy0,我们都知道动态代理是动态生成代理类对象,如果能看到动态生成的这个代理类,是不是能更好的理解动态代理的原理?

细心的同学可能已经看到以上代码中有一行比较特殊的代码,这行代码的作用是把 jdk.proxy.ProxyGenerator.saveGeneratedFiles 这个变量赋值为 true,这个变量为 true 时,将会在工程目录下生成 $Proxy0 的 class 文件(由于生成代理类的 ProxyGenerator 类在 sun.misc 包中,在 Android Studio 中无法调用,所以这里是在 Intellij 中写的 Demo 进行调用:

System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

这里有个需要注意的的点,在jdk1.8以及jdk1.8之前,这个属性是sun.misc.ProxyGenerator.saveGeneratedFiles,属性名称不对无法成功生成com.sun.proxy.$Proxy0这个文件。

  • (6)生成文件
package com.sun.proxy;

import dynamicProxy.ILawsuit;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

// $Proxy0 默认继承了 Proxy,所以这里解释了“只能针对接口(ILawsuit)创建代理类,不能针对类创建代理类”
public final class $Proxy0 extends Proxy implements ILawsuit {

    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m5;
    private static Method m3;
    private static Method m6;
    private static Method m0;

    public $Proxy0(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);
        }
    }

    public final void submit() throws  {
        try {
            super.h.invoke(this, m4, (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 void burden() throws  {
        try {
            super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void finish() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void defend() throws  {
        try {
            super.h.invoke(this, m6, (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"));
            m4 = Class.forName("dynamicProxy.ILawsuit").getMethod("submit");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m5 = Class.forName("dynamicProxy.ILawsuit").getMethod("burden");
            m3 = Class.forName("dynamicProxy.ILawsuit").getMethod("finish");
            m6 = Class.forName("dynamicProxy.ILawsuit").getMethod("defend");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

这个就是在src同级目录下生成的文件,也就是项目的根目录

通过代理类访问目标对象的方法,最终会通过 super.h.invoke() 回调到我们重写的 InvocationHandler 实现类的 invoke() 中。

3、动态代理原理
(1) 整体过程
/**
@params loader 用于从动态生成的class字节流中加载创建代理类
@params interfaces 委托对象实现的接口列表
@params h 代理类方法调用处理器
@return 返回动态创建的代理类
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
    throws IllegalArgumentException
{
    //要求代理逻辑对象非空
    Objects.requireNonNull(h);

    //根据传入的类构造器和接口对象,查找或者生成指定的代理类
    Class<?> cl = getProxyClass0(loader, intfs);

    //调用构造函数
    try {
        //拿到含有InvocationHandler类型参数的构造方法
        //目的是最后的类对象是跟我们的代理逻辑的对象相关联
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        
        //生成的类的修饰符不是公开的话
        if (!Modifier.isPublic(cl.getModifiers())) {
            //这里其实是拿到报异常的
            cons.setAccessible(true);
        }
        //通过反射拿到生成类的实例
        return cons.newInstance(new Object[]{h});
    }
}

其中的constructorParams是来自private static final Class<?>[] constructorParams ={ InvocationHandler.class }。

newProxyInstance动态创建代理类的步骤是

  • 校验代理类方法调用处理程序h不能为空
  • 动态生成代理类class文件格式字节流
  • 通过loader加载创建代表代理类的class对象
  • 根据代理类的构造器创建代理类并返回
(2)如何生成代理类的Class对象
 private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

再看proxyCache.get的实现,其中proxyCache是WeakCache的实现对象:

 //WeakCache.java
/**
@params key 此处是类加载器loader
@params parameter 此处是代理类接口列表
*/
public V get(K key, P parameter) {
        //此处要求代理类接口不能为空
        Objects.requireNonNull(parameter);
      
        expungeStaleEntries();
        //生成CacheKey对象
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        //根据cachekey获取键值对valuesMap, valuesMap的key是接口列表的包装类,value是动态生成代理类的包装类
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        //根据代理类接口生成的key
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //动态生成代理类的包装类
        Supplier<V> supplier = valuesMap.get(subKey);
        //生成动态代理类的工厂类
        Factory factory = null;

        while (true) {
            //如果动态代理类包装类supplier不为空,则使用supplier 中的工厂类factory加载动态生成的class文件格式的代理类的字节流
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                //此处是factory加载动态生成的class文件格式的代理类的字节流的实现
                V value = supplier.get();
                if (value != null) {
                    //此处返回动态生成的代理类
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            //如果动态生成代理类的工厂类为空,则创建新的工厂类
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }
           
            if (supplier == null) {
               //工厂类的包装类为空,则创建新的包装类supplier 
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
               //工厂类的包装类不为空,则替换包装类中的工作累
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

由上面的代码,大概知道通过map来存储动态生成的代理类,其中key是接口的包装类,value是动态代理类的包装类。

key的生成是通过subKeyFactory,subKeyFactory是KeyFactory的实现类,其实现很简单,只是对代理类接口进行包装:

private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }

private static final class Key1 extends WeakReference<Class<?>> {
        private final int hash;

        Key1(Class<?> intf) {
            super(intf);
            this.hash = intf.hashCode();
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            Class<?> intf;
            return this == obj ||
                   obj != null &&
                   obj.getClass() == Key1.class &&
                   (intf = get()) != null &&
                   intf == ((Key1) obj).get();
        }
    }

value是生成动态代理类的包装类,此包装类是实现了Supplier接口的Factory类,通过Factory的get方法动态生成代理类:

@Override
        public synchronized V get() { // serialize access
            // re-check
            //从map中获取已经生成的动态代理类的包装类
            Supplier<V> supplier = valuesMap.get(subKey);
            if (supplier != this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            V value = null;
            try {
                //通过valueFactory的apply方法生成动态代理类
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // the only path to reach here is with non-null value
            assert value != null;

            // wrap value with CacheValue (WeakReference)
            CacheValue<V> cacheValue = new CacheValue<>(value);

            // try replacing us with CacheValue (this should always succeed)
            if (valuesMap.replace(subKey, this, cacheValue)) {
                // put also in reverseMap
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }

这里核心的实现是valueFactory的apply方法,valueFactory是ProxyClassFactory的实现类,我们来看下ProxyClassFactory的apply方法,看其是怎么实现生成动态代理类的:

public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            //获取代理类接口的class对象,并校验是否是接口,如果不是则抛出错误
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
            //动态代理类的包名
            String proxyPkg = null;     // package to define proxy class in
            //动态代理类的访问权限
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                //根据代理类接口生成包名和访问权限
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use the default package.
                proxyPkg = "";
            }

            {
                // Android-changed: Generate the proxy directly instead of calling
                // through to ProxyGenerator.
                //获取代理类接口的方法列表,并进行排序和返回类型校验
                List<Method> methods = getMethods(interfaces);
                Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
                validateReturnTypes(methods);
                //获取方法类别的异常列表
                List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
                //方法列表转为方法数组
                Method[] methodsArray = methods.toArray(new Method[methods.size()]);
               //异常列表转为异常数组
                Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);

                /*
                 * Choose a name for the proxy class to generate.
                 */
                //生成代理类唯一名称
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
                //根据类名、接口、类加载器、方法列表、异常列表,按照class文件格式先生成字节流,再生成动态代理类
                return generateProxy(proxyName, interfaces, loader, methodsArray,
                                     exceptionsArray);
            }
        }

//native方法,其实现原理是根据类名、接口、类加载器、方法列表、异常列表,按照class文件格式先生成字节流,再生成动态代理类
@FastNative
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
                                                 ClassLoader loader, Method[] methods,
                                                 Class<?>[][] exceptions);

Android 代理模式(动态代理)及其原理分析
动态代理原理及在 Android 中的应用
Android开发如何理解Java静态代理 动态代理
动态代理原理解析

代理模式是一种结构型设计模式,它提供一个代理对象来代表另一个对象。在代理模式,有一个被称为实际对象(Subject)和一个被称为代理对象(Proxy)的介,代理对象持有实际对象的引用,并且可以控制对实际对象的访问。代理模式的主要目的是在不修改原始对象的情况下,为原始对象添加额外的逻辑处理。 代理模式分为多种型,如远程代理、虚拟代理、保护代理等,它们各自有不同的应用场景: - 远程代理:为远程对象提供一个本地代表。 - 虚拟代理:根据需要创建开销大的对象,通过虚拟代理控制访问这些对象的过程。 - 保护代理:控制对原始对象的访问权限,例如进行权限检查。 代理模式的优点包括: 1. 能够控制对真实对象的访问,并在访问前后添加额外的逻辑。 2. 可以通过代理对象实现延迟加载,即在实际需要才创建真实对象。 3. 增强了对真实对象的封装,并且可以避免对真实对象的重复引用。 在C#实现代理模式通常涉及以下步骤: 1. 定义一个接口或抽象,声明真实对象代理对象需要实现方法。 2. 实现真实对象,按照接口或抽象的要求实现具体方法。 3. 实现代理,它同样实现接口或抽象,并在方法持有真实对象的引用,通过调用真实对象方法来执行所需的操作,同可以添加额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值