1. 程式人生 > >設計模式之代理模式(一)

設計模式之代理模式(一)

一、什麼是代理模式

定義:為其他物件提供一種代理以控制對這個物件的訪問。在某些情況下,一個物件不適合或者不能直接引用另一個物件,而代理物件可以在客戶端和目標物件之間起到中介的作用。一個類代表另一個類的功能。這種型別的設計模式屬於結構型模式。

組成: 抽象角色:(主題)通過介面或抽象類宣告真實角色實現的業務方法。 代理角色:實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並可以附加自己的操作。 真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色呼叫。

二、為什麼要使用代理模式

意圖:為其他物件提供一種代理以控制對這個物件的訪問。

主要解決:在直接訪問物件時帶來的問題,比如說:要訪問的物件在遠端的機器上。在面向物件系統中,有些物件由於某些原因(比如物件建立開銷很大,或者某些操作需要安全控制,或者需要程序外的訪問),直接訪問會給使用者或者系統結構帶來很多麻煩,我們可以在訪問此物件時加上一個對此物件的訪問層。

應用例項:1、Windows 裡面的快捷方式。2、買火車票不一定在火車站買,也可以去代售點。 3、spring aop。

優點: 1、職責清晰。

    被代理物件只負責自己實際的業務邏輯,不關心其他非本身的職責。並將其他事務可以通過代理類處理。

       2、高擴充套件性。

    無論被代理物件如何改變,只要代理類和被代理類都實現了統一介面,都不同修改代理類,而且即使擴充套件了新的被代理類,代理類也可以使用,只要建立代理類的時候傳入對應的被代理類物件。

 

    3、智慧化。

    這主要體現在動態代理中,下面會講解動態代理。如果有興趣瞭解Spring的AOP,其實就是使用了動態代理。

缺點: 1、由於在客戶端和真實主題之間增加了代理物件,因此有些型別的代理模式可能會造成請求的處理速度變慢。

       2、實現代理模式需要額外的工作,有些代理模式的實現非常複雜。

注意事項: 1、和介面卡模式的區別:介面卡模式主要改變所考慮物件的介面,而代理模式不能改變所代理類的介面。

         2、和裝飾器模式的區別:裝飾器模式為了增強功能,而代理模式是為了加以控制。

三、如何用代理模式

  我們舉個示例,比如在娛樂圈,客戶與藝人進行商業合作,一般都不是與藝人直接聯絡,簽訂時間、地點、薪酬等合同,而是

找藝人的經紀人商討,那麼這裡商藝活動就是抽象物件(主題),藝人就被代理物件,經紀人就是代理物件。

程式碼示例:

package com.pattern.proxy;

/**
 *  抽象介面 演藝
 */
public interface Performance {

    public void Sing(String name , String address, String date);//誰在哪個時間哪個地點唱歌

    public void dance(String name , String address, String date); //誰在哪個時間哪個地點跳舞

    public void perform(String name , String address, String date);//誰在哪個時間哪個地點表演
}
抽象物件(主題)
package com.pattern.proxy;

/**
 *  被代理物件 藝人
 */
public class Artist implements Performance{

    private Agent agent;// 獲取指定代理人物件

    //獲取指定的代理人物件
    public Performance getAgent(){
        agent = new Agent(this);
        return agent;
    }


    @Override
    public void Sing(String name, String address, String date) {
        if (agent == null){
            System.out.println("請使用指定的代理類");
        }else
        System.out.println(date+"    "+name  +"在"+address +"rap了一首xX");
    }

    @Override
    public void dance(String name, String address, String date) {
        if (agent == null){
            System.out.println("請使用指定的代理類");
        }else
            System.out.println( date+"    "+name  +"在"+address +"跳了一個芭蕾");
    }

    @Override
    public void perform(String name, String address, String date) {
        if (agent == null){
            System.out.println("請使用指定的代理類");
        }else
            System.out.println(date+"    "+name  +"在"+address +"表演了打籃球");
    }
}
被代理物件
package com.pattern.proxy;

/**
 * 代理物件 經紀人
 * Created by wanbf on 2019/5/26.
 */
public class Agent  implements Performance{

    //儲存被代理人的例項
    private Performance performance;

    public Agent(Performance performance){

        this.performance = performance;
    }

    @Override
    public void Sing(String name, String address, String date) {
        performance.Sing(name,address,date);//這裡經紀人是不會唱歌的,執行藝人的唱歌 下同
    }

    @Override
    public void dance(String name, String address, String date) {
        performance.dance(name,address,date);
    }

    @Override
    public void perform(String name, String address, String date) {
        performance.perform(name,address,date);
    }
}
代理物件
public static void main(String[] args){

        Performance performance = new Artist().getAgent();

        performance.Sing("CXK","韓國", DateFormat.getDateInstance().format(new Date()));
        performance.dance("CXK","韓國",DateFormat.getDateInstance().format(new Date()));
        performance.perform("CXK","韓國",DateFormat.getDateInstance().format(new Date()));

    }
輸出:
2019-5-26    CXK在韓國rap了一首xX
2019-5-26    CXK在韓國跳了一個芭蕾
2019-5-26    CXK在韓國表演了打籃球
測試

上面我們是走指定的代理物件 執行方法;

那麼我們不通過代理方法來執行呢,

//不通過代理還執行
Performance performance = new Artist();

performance.Sing("CXK","韓國", DateFormat.getDateInstance().format(new Date()));
performance.dance("CXK","韓國",DateFormat.getDateInstance().format(new Date()));
performance.perform("CXK","韓國",DateFormat.getDateInstance().format(new Date()));

輸出:
請使用指定的代理類
請使用指定的代理類
請使用指定的代理類
不走代理方法

很顯然,不用代理方法是不能執行成功的

不是指定代理方法呢,

//不是指定的代理方法
Performance performance = new Agent(new Artist());

performance.Sing("CXK","韓國", DateFormat.getDateInstance().format(new Date()));
performance.dance("CXK","韓國",DateFormat.getDateInstance().format(new Date()));
performance.perform("CXK","韓國",DateFormat.getDateInstance().format(new Date()));
輸出:
請使用指定的代理類
請使用指定的代理類
請使用指定的代理類
不是指定的代理方法

顯然不是指定的代理方法也是執行不了的

 這個示例是強制代理模式,概念就是要從真是角色那裡查詢到代理角色,不允許直接訪問真實角色。

上層模組只需要呼叫Agent()獲取代理來訪問真實角色的所有方法,它根本就不需要產生一個代理角色,代理的管理已經由真實角色自己來完成。

後續講解一個 基本代理 、普通代理、虛擬代理模式 和動態代理模