設計模式之代理模式

代理模式

在代理模式(Proxy Pattern)中,一個類代表另一個類的功能。這種類型的設計模式屬於結構型模式。
在代理模式中,我們創建具有現有對象的對象,以便向外界提供功能接口。
介紹
意圖:爲其他對象提供一種代理以控制對這個對象的訪問。
主要解決:在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象由於某些原因(比如對象創建開銷很大,或者某些操作需要安全控制,或者需要進程外的訪問),直接訪問會給使用者或者系統結構帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層。
何時使用:想在訪問一個類時做一些控制。
如何解決:增加中間層。
關鍵代碼:實現與被代理類組合。
應用實例: 1、Windows 裏面的快捷方式。 2、豬八戒去找高翠蘭結果是孫悟空變的,可以這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實現了這個接口,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,所以說孫悟空是高翠蘭代理類。 3、買火車票不一定在火車站買,也可以去代售點。 4、一張支票或銀行存單是賬戶中資金的代理。支票在市場交易中用來代替現金,並提供對簽發人賬號上資金的控制。 5、spring aop。
優點: 1、職責清晰。 2、高擴展性。 3、智能化。
缺點: 1、由於在客戶端和真實主題之間增加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢。 2、實現代理模式需要額外的工作,有些代理模式的實現非常複雜。

靜態代理模式

靜態代理在使用時,需要定義接口或者父類,被代理對象和代理對象一起實現相同的接口或者繼承相同的父類。
比如訪問數據庫操作類
這裏寫圖片描述

代碼:

目標對象

public interface IUserDao {
    void save();
}

實際對象

public class UserDao implements IUserDao {
    @Override
    public void save() {
        System.out.println("wwwwww");
    }
}

代理對象

public class UserDaoProxy implements IUserDao {
    private IUserDao target;
    public UserDaoProxy(IUserDao target){
        this.target=target;
            }
    @Override
    public void save() {
        // TODO Auto-generated method stub
        target.save();
        }
}

客戶端

public static void main(String[] args) {
        // 目標對象
        UserDao userDao =new UserDao();
        //代理對象
        UserDaoProxy proxy =new UserDaoProxy(userDao);
        proxy.save();


    }

靜態代理模式優缺點:
1:可以在不修改目標對象的功能前提下,對目標功能擴展
2:缺點:因爲代理對象需要與目標對象實現一樣的接口,所以會有很多代理類,類太多。同時,一旦接口增加方法,目標對象與代理對象都要維護。(可以使用動態代理)

動態代理模式

動態代理有以下特點:
1:代理對象,不需要實現接口
2:代理對象的生成,是利用jdk的API,動態在內存中構建代理對象(需要我們指定創建代理對象/目標對象實現的接口類型)
3:動態代理也叫:jdk代理,接口代理

jdk中生成代理對象的API
代理類所在包:java.lang.reflect.Proxy
JDk實現代理只需要newProxyInstance方法,但是該方法需要接受三個參數

Static Object newProxyInstance(ClassLoader loader,Class

public class ProxyFactory {

    //維護一個目標對象
    private Object target;

    public ProxyFactory(Object target){
        this.target = target ;

    }

    //給目標對象生成代理對象

    public  Object getProxyInstance(){

        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                //執行目標方法
                Object returnVaObject=method.invoke(target, args);
                return returnVaObject;
            }
        });
    }
}

客戶端

public class AppTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        IUserDao targetDao =new UserDao();
        IUserDao proxyDao =(IUserDao)new ProxyFactory(targetDao).getProxyInstance();

        proxyDao.save();

    }

}

代理對象不需要實現接口,但是目標對象一定要實現接口,否則不能用動態代理。

Cglib代理模式

上面靜態代理和動態代理都是要求目標對象是實現一個接口的目標對象,但有時目標對象只是一個普通類,並沒有實現任何接口,這時候可以考慮使用以目標對象子類的方式類實現代理。
Cglib代理也叫子類代理,他是在內存中構建一個子類對象從而實現對目標對象功能的擴展。
1:jdk動態代理有一個限制,即目標對象必須實現一個或多個接口,如果想代理沒有實現接口的目標對象就要使用Cglib代理。
2:Cglib是一個強大的高性能的代碼生成包,可以運行期擴展java類與實現java接口。

Cglib子類實現方法
1:需要引入Cglib的jar文件,但是Spring核心包中已經包括Cglib功能
2:引入功能包後,就可以在內存中動態構建子類
3:代理的類不能爲final,否則報錯
4:目標對象的方法如果爲final/static,那麼就不會被攔截,即不會執行目標對象額外的業務方法。

目標對象

public class UerDao {

    public void save() {
        System.out.println("wwwwww");

    }

}

代理工廠

public class ProxyFactoryCglib implements MethodInterceptor {
    //維護目標對象
    private Object targetObject;

    public ProxyFactoryCglib( Object targetObject) {

        this.targetObject =targetObject ;

    }

    public Object getProxyInstance(){
        //工具類
        Enhancer enhancer =  new Enhancer();
        //設置父類
        enhancer.setSuperclass(targetObject.getClass());
        //設置回調函數
        enhancer.setCallback(this);
        //創建子類(代理對象)
        return enhancer.create();
    }

    @Override
    public Object intercept(Object arg0, Method method, Object[] args,
            MethodProxy arg3) throws Throwable {
        Object returnvalue= method.invoke(targetObject, args);
        return returnvalue;
    }

}

客戶端

public class AppTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        UerDao dao = new UerDao();
        UerDao proxyDao2=(UerDao)new ProxyFactoryCglib(dao).getProxyInstance();
        proxyDao2.save();

    }

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