设计模式-静态代理和动态代理

一、静态代理模式

在我看来,代理模式就是现实中的各种外包。

例如工厂招聘流程:前期招工场地确定以及布置 -> 招工宣传 -> 对应聘者的考核 -> 工资的确认 ->工人进厂然而,对于工厂来说,这一系列的动作中只有“工人进厂”是他们的核心需求,前期的招聘宣传组织考核并不是他们所擅长的,并且耗时耗力。
因此,本着用心做好自己擅长的事的原则,他们找到了人力资源公司,将招工的需求外包给人力资源公司,而工厂要做的只是专注于接收招聘而来的工人,处理他们在工厂内的一切事宜

代理模式在我看来,就是专注于自己的核心需求,针对那些实现核心需求的过程中也不可少的附加功能,可以交给代理去实现,让自己的职责更简单 纯粹。

静态代理demo实例:

package designmode.proxymode.staticproxy;

/**
 * @author pcf
 * @date 2023/3/7 16:42
 */
public interface Recruit {

    // 招聘
    void recruit();
}
package designmode.proxymode.staticproxy;

/**
 * 需要招人的工厂 : 我只想快速招到工人
 * @author pcf
 * @date 2023/3/7 16:40
 */
public class Factory implements Recruit {
    @Override
    public void recruit() {
        System.out.println("招工成功!");
    }
}
package designmode.proxymode.staticproxy;

/**
 * 人力资源公司代理招工
 * @author pcf
 * @date 2023/3/7 16:43
 */
public class HumanResourcesCompanyProxy implements Recruit{
    private Factory factory;

    public HumanResourcesCompanyProxy(Factory factory) {
        this.factory = factory;
    }

    @Override
    public void recruit() {
        // 人力资源公司:确定面试场地
        findArea();
        // 人力资源公司:发布招工信息
        releaseInformation();
        // 人力资源公司:对应聘者考核筛选
        filterPeople();
        // 人力资源公司: 给工人订工资,送工人去工厂
        dealWithPeople();
        // 工厂:接收到工人
        factory.recruit();
        // 人力资源公司: 与工厂结算利润
        settlementWithFactory();
    }

    private void findArea() {
        System.out.println("人力资源公司:确定面试场地。");
    }

    public void releaseInformation() {
        System.out.println("人力资源公司:发布招工信息。");
    }

    public void filterPeople() {
        System.out.println("人力资源公司:对应聘者考核筛选");
    }

    public void dealWithPeople() {
        System.out.println("人力资源公司: 给工人订工资,送工人去工厂");
    }

    public void settlementWithFactory() {
        System.out.println("人力资源公司: 与工厂结算利润");
    }

}
package designmode.proxymode.staticproxy;

import org.junit.Test;

/**
 * @author pcf
 * @date 2023/3/7 16:54
 */
public class TestStaticProxy {
    /**
     * 在我看来,代理模式就是现实中的各种外包。
     * 对于此例来说:
     * 招工是一系列的动作简化来看:前期招工场地确定 -> 招工宣传 -> 对应聘者的考核 -> 工资的确认 -> 工人进厂
     * 然而,对于工厂来说,这一系列的动作中只有“工人进厂”是他们的核心需求,前期的招聘宣传组织考核并不是他们
     * 所擅长的,并且耗时耗力。
     * 因此,让专业的人干专业的事,他们找到了人力资源公司,将招工的需求外包给人力资源公司,
     * 而工厂要做的只是专注于接收招聘而来的工人,处理他们在工厂内的一切事宜
     *
     * 代理模式在我看来,就是专注于自己的核心需求,针对那些实现核心需求的过程中也不可少的附加功能,可以交给
     * 代理去实现,让自己的职责更简单 纯粹
     *
     */
    @Test
    public void testStaticProxy() {
        // 该工厂招人
        Factory factory = new Factory();
        // 工厂找到人力资源公司要人
        HumanResourcesCompanyProxy humanResourcesCompany = new HumanResourcesCompanyProxy(factory);
        // 人力资源公司给工厂拉人
        humanResourcesCompany.recruit();
    }
}

二、动态代理模式

为什么会有动态代理呢? 因为静态代理有时候不太好用,有点麻烦。
静态代理是项目运行之前就写好的代理,可以理解为是针对某个角色已定的代理方案。
在上面的例子中:
如果此时有其它的工厂也要招工,委托这个人力资源公司。比如之前是电子厂,现在是渔场,可能面向人群、考核要求、附加条件等都发生了变化。这时之前的代理不适配了那么这个人力资源公司就要拿出来另一套符合该工厂要求的招聘方案(新创建一个代理)。这显然是很麻烦的,可能针对一个新厂子就要先创建一个新的代理。

这时候就要用动态代理了:
相对比与静态代理项目运行前就先写好的代理,动态代理是在项目运行后,在需要的时候动态生成代理。我们只需要在创建代理的时候把需要附加的功能在代理中实现即可。

动态代理demo实例:
package designmode.proxymode.dynamicproxy;

/**
 * @author pcf
 * @date 2023/3/7 16:42
 */
public interface Recruit {

    // 招聘
    void recruit();
}
package designmode.proxymode.dynamicproxy;

/**
 * 需要招人的工厂 : 我只想快速招到工人
 * @author pcf
 * @date 2023/3/7 16:40
 */
public class Factory implements Recruit {
    @Override
    public void recruit() {
        System.out.println("招工成功!");
    }
}
package designmode.proxymode.dynamicproxy;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author pcf
 * @date 2023/3/8 11:47
 */
public class TestDynamicProxy {
    /**
     * 为什么会有动态代理呢? 因为静态代理有时候不太好用,有点麻烦。
     * 静态代理是项目编译之前就写好的代理,可以理解为是针对某个角色已定的代理方案。
     * 在上面的例子中:
     * 如果此时有其它的工厂也要招工,委托这个人力资源公司。比如之前是电子厂,现在是渔场,可能面向人群、考核要求、附加条件等
     * 都发生了变化。这时之前的代理不适配了,那么这个人力资源公司就要拿出来另一套符合该工厂要求的招聘方案(新创建一个代理)。
     * 这显然是很麻烦的,可能针对一个新厂子就要先创建一个新的代理。
     *
     * 这时候就要用动态代理了:
     * 相对比与静态代理运行前就先写好的代理,动态代理是在项目运行后,在需要的时候动态生成代理。我们只需要在创建代理的时候把
     * 需要附加的功能在代理中实现即可。
     *
     * 这样的话,不论针对什么操作,我们都可以通过动态代理,把核心业务和附加功能分隔开。
     * 如此例中:让Factory类更加专注于实现自己的工厂和工人管理,其它招聘事宜交给代理去完成。
     *
     *
     * 总结下来:代理就是对原有业务的加强和补充,让类更关注于本类中原有功能的实现,多出来的附加功能,如日志打印、事务控制,
     * 交给代理去做。
     * 事实上spring的AOP就是通过动态代理实现的。
     *
     */

    @Test
    public void testDynamicProxy() {

        // 使用动态代理对象: 指的是在程序运行过程中动态通过代码方式为指定的类生成动态代理对象
        // proxy: 用来生成动态对象的类
        // 目标类
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 取当前线程的类加载器
        Class[] classes = {Recruit.class};
        /**
         * @Note  为目标类生成动态代理对象
         *
         * @Param classLoader  类加载器
         *                      需要底层的类加载器去读取到目标类的class文件并加载到内存中,然后才能对应的为其生成动态代理对象
         * @Param classes      目标类的接口的类型的数组
         *                      一个类可以实现多个接口,故用数组
         * @Param new InvocationHandler() {}   InvocationHandle接口类型
         *
         * @Return  userServiceProxy    创建好目标类的动态代理对象
         */
        Recruit factoryProxy = (Recruit) Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
            @Override
            /**
             *  @Param proxy Object
             *          当前创建好的代理对象
             *  @Param method Method
             *          当前代理对象执行的方法对象
             *  @Param args Object[]
             *          当前代理对象执行的方法的参数
             *
             * @Note  通过动态代理对象调用自己里面代理方法时会优先执行InvocationHandle类中的invoke
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 调用目标类中业务方法前的操作
                System.out.println("==============InvocationHandle类中的invoke=================");
                System.out.println("当前执行的方法: " + method.getName());
//                System.out.println("当前执行的方法的参数: " + args[0]); // 此示例中recruit是无参方法,因此打印参数会报错
                // 招工前的附加操作
                System.out.println("proxy-人力资源公司:确定面试场地");
                System.out.println("proxy-人力资源公司:发布招工信息");
                System.out.println("proxy-人力资源公司:对应聘者考核筛选");
                System.out.println("proxy-人力资源公司: 给工人订工资,送工人去工厂");
                // 招工
                Object invoke = method.invoke(new Factory(), args);
                // 招工后的附加操作
                System.out.println("proxy-人力资源公司:与工厂结算");
                return invoke;
            }
        });
        System.out.println(factoryProxy.getClass());
        factoryProxy.recruit();
    }
}

总结下来:代理就是对原有业务的加强和补充,让类更关注于本类中原有功能的实现,多出来的附加功能,如日志打印、事务控制,交给代理去做。
而相对于静态代理,动态代理的优势:
1、可以减少代理对象的个数,降低程序复杂度。
2、易于复杂业务的动态扩展。
事实上,spring的AOP就是通过动态代理实现的。

你可能感兴趣的:(设计模式-静态代理和动态代理)