設(shè)計(jì)模式-靜態(tài)代理和動態(tài)代理

一、靜態(tài)代理模式

在我看來,代理模式就是現(xiàn)實(shí)中的各種外包。

例如工廠招聘流程:前期招工場地確定以及布置 -> 招工宣傳 -> 對應(yīng)聘者的考核 -> 工資的確認(rèn) ->工人進(jìn)廠然而,對于工廠來說,這一系列的動作中只有“工人進(jìn)廠”是他們的核心需求,前期的招聘宣傳組織考核并不是他們所擅長的,并且耗時(shí)耗力。
因此,本著用心做好自己擅長的事的原則,他們找到了人力資源公司,將招工的需求外包給人力資源公司,而工廠要做的只是專注于接收招聘而來的工人,處理他們在工廠內(nèi)的一切事宜

代理模式在我看來,就是專注于自己的核心需求,針對那些實(shí)現(xiàn)核心需求的過程中也不可少的附加功能,可以交給代理去實(shí)現(xiàn),讓自己的職責(zé)更簡單 純粹。

靜態(tài)代理demo實(shí)例:

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();
        // 人力資源公司:發(fā)布招工信息
        releaseInformation();
        // 人力資源公司:對應(yīng)聘者考核篩選
        filterPeople();
        // 人力資源公司: 給工人訂工資,送工人去工廠
        dealWithPeople();
        // 工廠:接收到工人
        factory.recruit();
        // 人力資源公司: 與工廠結(jié)算利潤
        settlementWithFactory();
    }

    private void findArea() {
        System.out.println("人力資源公司:確定面試場地。");
    }

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

    public void filterPeople() {
        System.out.println("人力資源公司:對應(yīng)聘者考核篩選");
    }

    public void dealWithPeople() {
        System.out.println("人力資源公司: 給工人訂工資,送工人去工廠");
    }

    public void settlementWithFactory() {
        System.out.println("人力資源公司: 與工廠結(jié)算利潤");
    }

}
package designmode.proxymode.staticproxy;

import org.junit.Test;

/**
 * @author pcf
 * @date 2023/3/7 16:54
 */
public class TestStaticProxy {
    /**
     * 在我看來,代理模式就是現(xiàn)實(shí)中的各種外包。
     * 對于此例來說:
     * 招工是一系列的動作簡化來看:前期招工場地確定 -> 招工宣傳 -> 對應(yīng)聘者的考核 -> 工資的確認(rèn) -> 工人進(jìn)廠
     * 然而,對于工廠來說,這一系列的動作中只有“工人進(jìn)廠”是他們的核心需求,前期的招聘宣傳組織考核并不是他們
     * 所擅長的,并且耗時(shí)耗力。
     * 因此,讓專業(yè)的人干專業(yè)的事,他們找到了人力資源公司,將招工的需求外包給人力資源公司,
     * 而工廠要做的只是專注于接收招聘而來的工人,處理他們在工廠內(nèi)的一切事宜
     *
     * 代理模式在我看來,就是專注于自己的核心需求,針對那些實(shí)現(xiàn)核心需求的過程中也不可少的附加功能,可以交給
     * 代理去實(shí)現(xiàn),讓自己的職責(zé)更簡單 純粹
     *
     */
    @Test
    public void testStaticProxy() {
        // 該工廠招人
        Factory factory = new Factory();
        // 工廠找到人力資源公司要人
        HumanResourcesCompanyProxy humanResourcesCompany = new HumanResourcesCompanyProxy(factory);
        // 人力資源公司給工廠拉人
        humanResourcesCompany.recruit();
    }
}

二、動態(tài)代理模式

為什么會有動態(tài)代理呢? 因?yàn)殪o態(tài)代理有時(shí)候不太好用,有點(diǎn)麻煩。
靜態(tài)代理是項(xiàng)目運(yùn)行之前就寫好的代理,可以理解為是針對某個角色已定的代理方案。
在上面的例子中:
如果此時(shí)有其它的工廠也要招工,委托這個人力資源公司。比如之前是電子廠,現(xiàn)在是漁場,可能面向人群、考核要求、附加條件等都發(fā)生了變化。這時(shí)之前的代理不適配了那么這個人力資源公司就要拿出來另一套符合該工廠要求的招聘方案(新創(chuàng)建一個代理)。這顯然是很麻煩的,可能針對一個新廠子就要先創(chuàng)建一個新的代理。

這時(shí)候就要用動態(tài)代理了:
相對比與靜態(tài)代理項(xiàng)目運(yùn)行前就先寫好的代理,動態(tài)代理是在項(xiàng)目運(yùn)行后,在需要的時(shí)候動態(tài)生成代理。我們只需要在創(chuàng)建代理的時(shí)候把需要附加的功能在代理中實(shí)現(xiàn)即可。

動態(tài)代理demo實(shí)例:
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 {
    /**
     * 為什么會有動態(tài)代理呢? 因?yàn)殪o態(tài)代理有時(shí)候不太好用,有點(diǎn)麻煩。
     * 靜態(tài)代理是項(xiàng)目編譯之前就寫好的代理,可以理解為是針對某個角色已定的代理方案。
     * 在上面的例子中:
     * 如果此時(shí)有其它的工廠也要招工,委托這個人力資源公司。比如之前是電子廠,現(xiàn)在是漁場,可能面向人群、考核要求、附加條件等
     * 都發(fā)生了變化。這時(shí)之前的代理不適配了,那么這個人力資源公司就要拿出來另一套符合該工廠要求的招聘方案(新創(chuàng)建一個代理)。
     * 這顯然是很麻煩的,可能針對一個新廠子就要先創(chuàng)建一個新的代理。
     *
     * 這時(shí)候就要用動態(tài)代理了:
     * 相對比與靜態(tài)代理運(yùn)行前就先寫好的代理,動態(tài)代理是在項(xiàng)目運(yùn)行后,在需要的時(shí)候動態(tài)生成代理。我們只需要在創(chuàng)建代理的時(shí)候把
     * 需要附加的功能在代理中實(shí)現(xiàn)即可。
     *
     * 這樣的話,不論針對什么操作,我們都可以通過動態(tài)代理,把核心業(yè)務(wù)和附加功能分隔開。
     * 如此例中:讓Factory類更加專注于實(shí)現(xiàn)自己的工廠和工人管理,其它招聘事宜交給代理去完成。
     *
     *
     * 總結(jié)下來:代理就是對原有業(yè)務(wù)的加強(qiáng)和補(bǔ)充,讓類更關(guān)注于本類中原有功能的實(shí)現(xiàn),多出來的附加功能,如日志打印、事務(wù)控制,
     * 交給代理去做。
     * 事實(shí)上spring的AOP就是通過動態(tài)代理實(shí)現(xiàn)的。
     *
     */

    @Test
    public void testDynamicProxy() {

        // 使用動態(tài)代理對象: 指的是在程序運(yùn)行過程中動態(tài)通過代碼方式為指定的類生成動態(tài)代理對象
        // proxy: 用來生成動態(tài)對象的類
        // 目標(biāo)類
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 取當(dāng)前線程的類加載器
        Class[] classes = {Recruit.class};
        /**
         * @Note  為目標(biāo)類生成動態(tài)代理對象
         *
         * @Param classLoader  類加載器
         *                      需要底層的類加載器去讀取到目標(biāo)類的class文件并加載到內(nèi)存中,然后才能對應(yīng)的為其生成動態(tài)代理對象
         * @Param classes      目標(biāo)類的接口的類型的數(shù)組
         *                      一個類可以實(shí)現(xiàn)多個接口,故用數(shù)組
         * @Param new InvocationHandler() {}   InvocationHandle接口類型
         *
         * @Return  userServiceProxy    創(chuàng)建好目標(biāo)類的動態(tài)代理對象
         */
        Recruit factoryProxy = (Recruit) Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
            @Override
            /**
             *  @Param proxy Object
             *          當(dāng)前創(chuàng)建好的代理對象
             *  @Param method Method
             *          當(dāng)前代理對象執(zhí)行的方法對象
             *  @Param args Object[]
             *          當(dāng)前代理對象執(zhí)行的方法的參數(shù)
             *
             * @Note  通過動態(tài)代理對象調(diào)用自己里面代理方法時(shí)會優(yōu)先執(zhí)行InvocationHandle類中的invoke
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 調(diào)用目標(biāo)類中業(yè)務(wù)方法前的操作
                System.out.println("==============InvocationHandle類中的invoke=================");
                System.out.println("當(dāng)前執(zhí)行的方法: " + method.getName());
//                System.out.println("當(dāng)前執(zhí)行的方法的參數(shù): " + args[0]); // 此示例中recruit是無參方法,因此打印參數(shù)會報(bào)錯
                // 招工前的附加操作
                System.out.println("proxy-人力資源公司:確定面試場地");
                System.out.println("proxy-人力資源公司:發(fā)布招工信息");
                System.out.println("proxy-人力資源公司:對應(yīng)聘者考核篩選");
                System.out.println("proxy-人力資源公司: 給工人訂工資,送工人去工廠");
                // 招工
                Object invoke = method.invoke(new Factory(), args);
                // 招工后的附加操作
                System.out.println("proxy-人力資源公司:與工廠結(jié)算");
                return invoke;
            }
        });
        System.out.println(factoryProxy.getClass());
        factoryProxy.recruit();
    }
}

總結(jié)下來:代理就是對原有業(yè)務(wù)的加強(qiáng)和補(bǔ)充,讓類更關(guān)注于本類中原有功能的實(shí)現(xiàn),多出來的附加功能,如日志打印、事務(wù)控制,交給代理去做。
而相對于靜態(tài)代理,動態(tài)代理的優(yōu)勢:
1、可以減少代理對象的個數(shù),降低程序復(fù)雜度。
2、易于復(fù)雜業(yè)務(wù)的動態(tài)擴(kuò)展。
事實(shí)上,spring的AOP就是通過動態(tài)代理實(shí)現(xiàn)的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容