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

1、什麼是代理模式

定義:爲其餘對象提供一種代理以控制對這個對象的訪問。在某些狀況下,一個對象不適合或者不能直接引用另外一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用。一個類表明另外一個類的功能。這種類型的設計模式屬於結構型模式。java

組成:
抽象角色(主題):經過接口或抽象類聲明真實角色實現的業務方法。
代理角色(代理對象):實現抽象角色,是真實角色的代理,經過真實角色的業務邏輯方法來實現抽象方法,並能夠附加本身的操做。
真實角色(被代理對象):實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色調用。

2、爲何要使用代理模式

意圖:爲其餘對象提供一種代理以控制對這個對象的訪問。spring

主要解決:在直接訪問對象時帶來的問題,好比說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象因爲某些緣由(好比對象建立開銷很大,或者某些操做須要安全控制,或者須要進程外的訪問),直接訪問會給使用者或者系統結構帶來不少麻煩,咱們能夠在訪問此對象時加上一個對此對象的訪問層。設計模式

應用實例:一、Windows 裏面的快捷方式。二、買火車票不必定在火車站買,也能夠去代售點。 三、spring aop。安全

優勢: 一、職責清晰。ide

    被代理對象只負責本身實際的業務邏輯,不關心其餘非自己的職責。並將其餘事務能夠經過代理類處理。測試

       二、高擴展性。this

    不管被代理對象如何改變,只要代理類和被代理類都實現了統一接口,都不一樣修改代理類,並且即便擴展了新的被代理類,代理類也可使用,只要建立代理類的時候傳入對應的被代理類對象。spa

    三、智能化。設計

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

缺點: 一、因爲在客戶端和真實主題之間增長了代理對象,所以有些類型的代理模式可能會形成請求的處理速度變慢。

       二、實現代理模式須要額外的工做,有些代理模式的實現很是複雜。

注意事項: 一、和適配器模式的區別:適配器模式主要改變所考慮對象的接口,而代理模式不能改變所代理類的接口。

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

3、如何用代理模式

  咱們舉個示例,好比在娛樂圈,客戶與藝人進行商業合做,通常都不是與藝人直接聯繫,簽定時間、地點、薪酬等合同,而是

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

代碼示例:

首先咱們來看一個最基本的代理模式:

package com.pattern.proxy1;

/**
 *  抽象接口 演藝
 */
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.proxy1;

/**
 *  被代理對象 藝人
 */
public class Artist implements Performance {

    @Override
    public void Sing(String name, String address, String date) {
        System.out.println(date+"    "+name  +"在"+address +"rap了一首xX");
    }

    @Override
    public void dance(String name, String address, String date) {
        System.out.println( date+"    "+name  +"在"+address +"跳了一個芭蕾");
    }

    @Override
    public void perform(String name, String address, String date) {
        System.out.println(date+"    "+name  +"在"+address +"表演了打籃球");
    }
}
被代理對象
package com.pattern.proxy1;

/**
 * 代理對象 經紀人
 * 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) {
        System.out.println("經濟人和客戶肯定時間地點等一系列細節後...");
        performance.Sing(name,address,date);//這裏經紀人是不會唱歌的,執行藝人的唱歌 下同
    }

    @Override
    public void dance(String name, String address, String date) {
        System.out.println("經濟人和客戶肯定時間地點等一系列細節後...");
        performance.dance(name,address,date);
    }

    @Override
    public void perform(String name, String address, String date) {
        System.out.println("經濟人和客戶肯定時間地點等一系列細節後...");
        performance.perform(name,address,date);
    }
}
代理對象
package com.pattern.proxy1;

import java.text.DateFormat;
import java.util.Date;

/**
 * Created by wanbf on 2019/5/26.   這裏是最基本代理模式示例
 */
public class Main {

    public static void consumer(Performance performance){
        performance.Sing("CXK","韓國", DateFormat.getDateInstance().format(new Date()));
        performance.dance("CXK","韓國",DateFormat.getDateInstance().format(new Date()));
        performance.perform("CXK","韓國",DateFormat.getDateInstance().format(new Date()));
    }
    public static void main(String[] args){
        consumer(new Artist());
        System.out.println("----------------");
        consumer(new Agent(new Artist()));
    }

}
測試
輸出:
2019-5-27    CXK在韓國rap了一首xX
2019-5-27    CXK在韓國跳了一個芭蕾
2019-5-27    CXK在韓國表演了打籃球
----------------
經濟人和客戶肯定時間地點等一系列細節後...
2019-5-27    CXK在韓國rap了一首xX
經濟人和客戶肯定時間地點等一系列細節後...
2019-5-27    CXK在韓國跳了一個芭蕾
經濟人和客戶肯定時間地點等一系列細節後...
2019-5-27    CXK在韓國表演了打籃球
輸出

從示例中咱們能夠看出 客戶直接調用 被代理人對象 和 代理人對象的區別在於一些額外的操做從 「實際」對象中 分離到不一樣的地方,特別是當你可以很容易的作出修改,從沒有額外操做轉爲使用這些操做。

那麼在示例中客戶(抽象對象、主題接口)想要的只是藝人的表演,而藝人(被代理對象)只管表演,那麼其中一些好比時間地點細節操做 交給經紀人(代理對象) 去完成,而後在調用藝人去完成表演。

在實際項目中,額外的操做多數是日誌記錄操做。

 再來看一個普通代理模式:

package com.pattern.proxy2;

/**
 *  抽象接口 演藝
 */
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.proxy2;

/**
 *  被代理對象 藝人
 */
public class Artist implements Performance {

    //經過構造方法將代理傳進來
    public Artist( Performance performance) {
        if (performance == null){
            System.out.println("不是經過代理人進來的");
        }
    }

    @Override
    public void Sing(String name, String address, String date) {
        System.out.println(date+"    "+name  +"在"+address +"rap了一首xX");
    }

    @Override
    public void dance(String name, String address, String date) {
        System.out.println( date+"    "+name  +"在"+address +"跳了一個芭蕾");
    }

    @Override
    public void perform(String name, String address, String date) {
        System.out.println(date+"    "+name  +"在"+address +"表演了打籃球");
    }
}
被代理對象
package com.pattern.proxy2;

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

    //保存被代理人的實例
    private Performance performance;

    public Agent(){
        //經過構造方法建立 Artist,將本身傳遞出去
        this.performance = new Artist(this);
    }

    @Override
    public void Sing(String name, String address, String date) {
        System.out.println("經濟人和客戶肯定時間地點等一系列細節後...");
        performance.Sing(name,address,date);//這裏經紀人是不會唱歌的,執行藝人的唱歌 下同
    }

    @Override
    public void dance(String name, String address, String date) {
        System.out.println("經濟人和客戶肯定時間地點等一系列細節後...");
        performance.dance(name,address,date);
    }

    @Override
    public void perform(String name, String address, String date) {
        System.out.println("經濟人和客戶肯定時間地點等一系列細節後...");
        performance.perform(name,address,date);
    }
}
代理對象
package com.pattern.proxy2;

import java.text.DateFormat;
import java.util.Date;

/**
 * Created by wanbf on 2019/5/26.   這裏是普通代理模式示例
 */
public class Main {

    public static void consumer(Performance performance){
        performance.Sing("CXK","韓國", DateFormat.getDateInstance().format(new Date()));
        performance.dance("CXK","韓國",DateFormat.getDateInstance().format(new Date()));
        performance.perform("CXK","韓國",DateFormat.getDateInstance().format(new Date()));
    }
    public static void main(String[] args){
        Performance performance = new Agent();
        consumer(performance);
        System.out.println("----------------");
      //  consumer(new Agent(new Artist()));
    }

}
測試
輸出:
經濟人和客戶肯定時間地點等一系列細節後...
2019-5-27    CXK在韓國rap了一首xX
經濟人和客戶肯定時間地點等一系列細節後...
2019-5-27    CXK在韓國跳了一個芭蕾
經濟人和客戶肯定時間地點等一系列細節後...
2019-5-27    CXK在韓國表演了打籃球
----------------
輸出

從測試代碼能夠看出,咱們調用 是用知道被代理對象 真實角色是誰的,只有代理對象知道,那麼屏蔽了真實角色的變動 對整個模塊的影響。

 在看一個強制代理模式

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()獲取代理來訪問真實角色的全部方法,它根本就不須要產生一個代理角色,代理的管理已經由真實角色本身來完成。

後續講解一個 虛擬代理模式 和動態代理模式。

相關文章
相關標籤/搜索