java 設計模式 代理模式

代理模式的作用是:爲其他對象提供一種代理以控制對這個對象的訪問。
在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。

靜態代理

涉及到的對象
代理類 CustommerProxy ,授代理類 ICustommer,分別都要實現接口
關係圖如下
這裏寫圖片描述

場景示例:
現假如我客戶Custommer類是由A程序員開發的,Custommer類中有一個dosometing方法。
現有程序員B,他是畢業生,剛過來,程序員A給他發了一個包,沒有源代碼,並跟小B說需要對這個方法進行優化,需要在調用dosometing之前先校驗該用戶是否登錄了。那麼問題來了,小B在不知道源代碼的情況下,如何進行代碼重構

由於小B比較優秀,很快就想到了代理模式,所以噹噹的就寫下了如下代碼
接口類,由於代理類和被代理類

package com.cmh.service;

public interface Custommer {
    void dosomething();

}

被代理類的實現類

public class ICustommer implements Custommer{

    @Override
    public void dosomething() {
        // TODO Auto-generated method stub
        System.out.println("I have something");
    }

}

代理類的實現類

public class CustommerProxy implements Custommer{

    private ICustommer custommer;

    public CustommerProxy(ICustommer custommer){
        this.custommer = custommer;
    }

    @Override
    public void dosomething() {
        // TODO Auto-generated method stub
        System.out.println("do something before");
        custommer.dosomething();
        System.out.println("do something after");
    }

}

測試類

public static void main(String[] args) {
        pack();
    }

    public static void pack(){
        ICustommer cus = new ICustommer();
        Custommer proxy = new CustommerProxy(cus);
        proxy.dosomething();
    }

小B覺得這個也太他媽簡單了,於是就屁顛屁顛的跟他老大小A說,so easy,準備聽聽他老大好好的誇他,他老大一看代碼,哎不錯哦,這小子是可塑之才,當場就跟他說,小夥子,不錯嘛,那我再考考你,假如現在項目出現了變動,就是說我不僅在Custommer 需要改這個邏輯,我在其他類也需要這個邏輯。那麼怎麼辦?

小B心理一陣低估,握草,你大爺,然後就屁顛屁顛的跑回去找相關的資料,突然一個字眼出現在了小B眼前,動態代理?

動態代理

動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不僅簡化了編程工作,而且提高了軟件系統的可擴展性,因爲Java 反射機制可以生成任意類型的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。 原來是利用反射的機制來實現的,今天我們不討論反射,我們看JDK的動態代理的實現。

若想實現 動態代理,就必須實現InvocationHandler 接口,InvocationHandler 的參數詳解

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

loader:  一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載

interfaces:  一個Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什麼接口,如果我提供了一組接口給它,那麼這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了

h:  一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上

小B給出的代碼:

接口和原先的實現類都沒變

package com.cmh.service;

public interface Custommer {
    void dosomething();
    void deletesomething();

}

實現類

package com.cmh.service;

public class ICustommer implements Custommer{

    @Override
    public void dosomething() {
        // TODO Auto-generated method stub
        System.out.println("I have something");
    }

    @Override
    public void deletesomething() {
        // TODO Auto-generated method stub
        System.out.println("I have Delete something");
    }

}

動態代理類

package com.cmh.proxy;

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

public class FactoryProxy implements InvocationHandler{

    private Object target;

    public Object getInstance(Object target) {    
        this.target = target;    
        //取得代理對象    
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        Object result=null;    
        System.out.println("before");    
        //執行方法   
        result=method.invoke(target, args);    
        System.out.println("after");
        return result;    
    }
}

測試類

public static void pack2(){
        FactoryProxy proxy = new FactoryProxy();
        Custommer custommer =(Custommer) proxy.getInstance(new ICustommer());
        custommer.dosomething();
        custommer.deletesomething();
    }

至此,動態類就差不多了,動態代理在spring AOP或者struts2 中的攔截器中用的比較多。

發佈了89 篇原創文章 · 獲贊 44 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章