java 中的設(shè)計(jì)模式

代理模式是什么

代理模式是一種設(shè)計(jì)模式,簡(jiǎn)單說(shuō)即是在不改變?cè)创a的情況下,實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的功能擴(kuò)展。

比如說(shuō)有一個(gè)買房的對(duì)象叫BuyHouser,這個(gè)對(duì)象有一個(gè)方法叫buyhouse();

    public void buyhouse() {
        System.out.println("我要買房");
    }

這是一個(gè)公共的買房對(duì)象,你不是很喜歡,所以你希望通過(guò)自己的方式買房。也就是對(duì)目標(biāo)對(duì)象BuyHouser的buyhouser方法進(jìn)行功能擴(kuò)展。

    public void buyhouse() {
        System.out.println("買房先準(zhǔn)備錢");
        System.out.println("我買房了");
        System.out.println("買完后裝修");
    }

就這樣可以通過(guò)修改相關(guān)代碼實(shí)現(xiàn)上面的需求,但是一些情況下相關(guān)的代碼是無(wú)法修改的,這個(gè)時(shí)候我們的代理模式就閃亮登場(chǎng)了

Java中代理模式分為兩種

  1. 靜態(tài)代理
  2. 動(dòng)態(tài)代理

先說(shuō)一說(shuō)靜態(tài)代理

  1. 先準(zhǔn)備一個(gè)接口,靜態(tài)代理要求目標(biāo)對(duì)象和代理對(duì)象實(shí)現(xiàn)同一個(gè)接口
public interface BuyHouse {
    void buyhouse();
}

  1. 然后準(zhǔn)備目標(biāo)對(duì)象實(shí)現(xiàn)這個(gè)接口
public class YouBuyHouse implements BuyHouse {
    @Override
    public void buyhouse() {
        System.out.println("我要買房");
    }
}
  1. 然后創(chuàng)建我們的代理對(duì)象
public class ProxyBuyHouse implements BuyHouse {
    //創(chuàng)建一個(gè)對(duì)象用于接收目標(biāo)對(duì)象 
    private BuyHouse buyHouse;
    //這里通過(guò)構(gòu)造器在代理類實(shí)例化的時(shí)候初始化目標(biāo)對(duì)象
    public ProxyBuyHouse(BuyHouse buyHouse){
        this.buyHouse=buyHouse;
    }
    //這里是代理對(duì)象的具體方法
    @Override
    public void buyhouse() {
        System.out.println("賣房先準(zhǔn)備錢");
        //這里調(diào)用了目標(biāo)對(duì)象的方法(這里是必須的,不然就算不上代理模式了)
        buyHouse.buyhouse();
        System.out.println("買完后裝修");
    }
}

代理已經(jīng)完成了,然后我們編寫(xiě)一個(gè)測(cè)試類來(lái)看看效果

public class BuyHouseTest {
    public static void main(String[] args) {
        //創(chuàng)建目標(biāo)對(duì)象
        BuyHouse youBuyHouse = new YouBuyHouse();
        //創(chuàng)建代理對(duì)象,并傳入目標(biāo)對(duì)象
        BuyHouse proxyBuyHouse = new ProxyBuyHouse(youBuyHouse);
        proxyBuyHouse.buyhouse();
    }
}

輸出結(jié)果是這樣的

賣房先準(zhǔn)備錢
我要買房
買完后裝修

總結(jié):其實(shí)這里做的事情無(wú)非就是,創(chuàng)建一個(gè)代理類ProxyBuyHouse,繼承了BuyHouse接口并實(shí)現(xiàn)了其中的方法。只不過(guò)這種實(shí)現(xiàn)特意包含了目標(biāo)對(duì)象的方法,正是這種特征使得看起來(lái)像是“擴(kuò)展”了目標(biāo)對(duì)象的方法。如果代理對(duì)象中只是簡(jiǎn)單地對(duì)buyhouse()方法做了另一種實(shí)現(xiàn)而沒(méi)有包含目標(biāo)對(duì)象的方法,也就不能算作代理模式了。所以這里的包含是關(guān)鍵。

缺點(diǎn):這種實(shí)現(xiàn)方式很直觀也很簡(jiǎn)單,但其缺點(diǎn)是代理對(duì)象必須提前寫(xiě)出,如果接口層發(fā)生了變化,代理對(duì)象的代碼也要進(jìn)行維護(hù)。如果能在運(yùn)行時(shí)動(dòng)態(tài)地寫(xiě)出代理對(duì)象,不但減少了一大批代理類的代碼,也少了不斷維護(hù)的煩惱,不過(guò)運(yùn)行時(shí)的效率必定受到影響。這種方式就是接下來(lái)的動(dòng)態(tài)代理。

2. 動(dòng)態(tài)代理(也叫JDK代理)

這里我們依據(jù)按照上面買房的例子進(jìn)行代理

public interface BuyHouse {
    void buyhouse();
}

public class YouBuyHouse implements BuyHouse {
    @Override
    public void buyhouse() {
        System.out.println("我要買房");
    }
}

動(dòng)態(tài)代理實(shí)現(xiàn)起來(lái)也很容易

public class BuyHoseTest2 {
    public static void main(String[] args) {
        //創(chuàng)建目標(biāo)對(duì)象
        YouBuyHouse youBuyHouse = new YouBuyHouse();
        //創(chuàng)建代理對(duì)象
        BuyHouse proxy = (BuyHouse) Proxy.newProxyInstance(
                youBuyHouse.getClass().getClassLoader(),
                youBuyHouse.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("買房先存錢");
                        Object returnValue = method.invoke(youBuyHouse,args);
                        System.out.println("買完房后裝修");
                        return returnValue;
                    }
                }
        );
        proxy.buyhouse();
    }
}

這里我們先創(chuàng)建了一個(gè)目標(biāo)對(duì)象,然后通過(guò) Proxy 類的靜態(tài)方法newProxyInstance獲取代理類對(duì)象

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

接收的三個(gè)參數(shù)依次為:

  • ClassLoader loader:指定當(dāng)前目標(biāo)對(duì)象使用類加載器,寫(xiě)法固定
  • Class<?>[] interfaces:目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型,寫(xiě)法固定
  • InvocationHandler h:事件處理接口,需傳入一個(gè)實(shí)現(xiàn)類(即代理類),一般直接使用匿名內(nèi)部類

總結(jié):這種方法因?yàn)榻?jīng)過(guò)jdk的封裝所以使用起來(lái)比較簡(jiǎn)單
缺點(diǎn):這種和靜態(tài)代理一樣需要實(shí)現(xiàn)接口才可以進(jìn)行相應(yīng)的操作,如果不想這樣可以通過(guò)spring 的Cglib代理實(shí)現(xiàn)(這個(gè)下次寫(xiě))

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

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

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