1. 程式人生 > >三分鐘帶您搞懂代理模式

三分鐘帶您搞懂代理模式

全文共1439字,預計閱讀時間:10分鐘

定義:

  代理模式(Proxy),為其他物件提供一種代理以控制對這個物件的訪問。   代理模式是一種比較貼近於生活的設計模式,現實生活中也有很多代理模式的例子:
    1. 住酒店不一定需要親自到酒店去,還可以通過微信支付下的同程藝龍來訂酒店。
    2. 我們可以通過中介去找房子,不用直接跟房東溝通(現實生活中,我們更希望直接跟房東溝通)
    3. 春運買票買不到,我們可以找黃牛替我們搶票
    4. 想訪問國外的網站,可以使用代理伺服器進行訪問。
  代理模式通常解決的問題是,我們沒有辦法直接訪問某一個物件,但是卻想使用這個物件的一些功能,這個時候我們就可以建立一個代理物件,通過訪問代理物件,間接的訪問這個物件。   我們想去旅行,但是沒有辦法提前去目的地訂酒店,所以我們通過同程藝龍來訂酒店。同程藝龍就是一個代理物件,他和酒店一樣,提供了訂酒店的方法。   我們沒有渠道去直接聯絡房東,所以我們可以通過中介公司租房,房東把租房這件事委託給了中介公司,這裡中介公司就是一個代理物件。代理物件除了呼叫真實物件的方法,還可以對方法進行增強。比如中介公司可以賺差價。

圖解:

 

 

 

  這裡可以看出,無論是代理物件和被代理物件,都實現了Subject介面,同時被代理物件作為代理物件的成員變數。這個結構與裝飾模式非常像,下圖是裝飾模式的示意圖:

那麼它們之間有什麼區別呢?

  首先從定義上可以看出,裝飾模式強調的是新增職責,而代理模式強調的是間接訪問。   其次從結構設計上來說,裝飾模式是將一個個功能進行拆分,使用時再動態的進行組裝,生成不同功能的物件。而代理模式卻是在編譯之前就已經確定了代理物件和被代理物件之間的關係。   最後就使用上來說,裝飾模式需要客戶端去組裝物件,而代理模式卻只需要客戶端去呼叫代理物件,代理物件和被代理物件的關係被封裝到了代理物件中,對使用者而言是無感的。

例項:

  這裡舉一個訂酒店的例項,小趙在同程藝龍上預定了橘子酒店,這裡酒店就是圖中的Subject,它提供了訂酒店、付款的方法,橘子酒店就是RealSubject,它是酒店的一個具體實現。而同程藝龍作為酒店的代理,提供優質的客戶服務,其中包括訂酒店前的電話確認、訂酒店後的客戶回訪、付款時提供紅包減免等。

程式碼:

/**
 * 酒店.
 *
 * @author jialin.li
 * @date 2019-12-27 11:37
 */
public interface Hotel {
    /** 訂酒店 **/
    void hotelBooking(String name);
    /** 付款 **/
    double pay();
}
/**
 * 橘子酒店.
 *
 * @author jialin.li
 * @date 2019-12-27 13:17
 */
public class OrangeHotel implements Hotel {

    @Override
    public void hotelBooking(String name) {
        System.out.println(name + ",歡迎入住橘子酒店");
    }

    @Override
    public double pay() {
        return 120d;
    }
}
/**
 * 同程藝龍
 *
 * @author jialin.li
 * @date 2019-12-27 13:20
 */
public class Elong implements Hotel{

    private Hotel hotel;

    public Elong() {
        hotel = new OrangeHotel();
    }

    @Override
    public void hotelBooking(String name) {
        System.out.println(confirm(name));
        hotel.hotelBooking(name);
        System.out.println(callback(name));
    }

    @Override
    public double pay() {
        return useHongbao(hotel.pay());
    }

    private String confirm(String name){
        return "親愛的"+name+"您預定了橘子酒店,記得入住哦!";
    }

    private String callback(String name){
        return "親愛的"+name+"您的入住已經結束,有問題請及時反饋!";
    }

    private double useHongbao(double price){
        return price - 50.0d;
    }
}
/**
 * 測試類.
 *
 * @author jialin.li
 * @date 2019-12-27 13:36
 */
public class Main {
    public static void main(String[] args) {
        String xiaozhao = "小趙";
        Elong elong = new Elong();
        elong.hotelBooking(xiaozhao);
        System.out.print("共花費了:");
        System.out.println(elong.pay());
    }
}

結果:

親愛的小趙您預定了橘子酒店,記得入住哦!
小趙,歡迎入住橘子酒店
親愛的小趙您的入住已經結束,有問題請及時反饋!
共花費了:70.0

有沒有什麼問題?

  可以看出,我們在代理類中直接引用了被代理物件,所以代理類和被代理類是一種一對一的關係,即我們需要為每一個被代理類,建立一個代理類。   假設我們現在有一個打點的需求,要為系統中的一批物件增加記錄日誌的方法,如果使用代理模式,就要為這一批物件建立代理類,這樣的工作量是無疑是巨大的。那麼有沒有什麼辦法可以讓我們可以少寫或者不寫代理類,卻能完成代理功能呢?這就要引出了我們要講的一個概念——動態代理(動態代理涉及到、反射類載入的一些知識,所以在下一篇文章中講解) 期待您的關注、推薦、收藏,同時也期待您的糾錯和批評。