全文共1439字,預計閱讀時間:10分鍾
定義:
代理模式(Proxy),為其他對象提供一種代理以控制對這個對象的訪問。
代理模式是一種比較貼近於生活的設計模式,現實生活中也有很多代理模式的例子:
-
- 住酒店不一定需要親自到酒店去,還可以通過微信支付下的同程藝龍來訂酒店。
- 我們可以通過中介去找房子,不用直接跟房東溝通(現實生活中,我們更希望直接跟房東溝通)
- 春運買票買不到,我們可以找黃牛替我們搶票
- 想訪問國外的網站,可以使用代理服務器進行訪問。
代理模式通常解決的問題是,我們沒有辦法直接訪問某一個對象,但是卻想使用這個對象的一些功能,這個時候我們就可以創建一個代理對象,通過訪問代理對象,間接的訪問這個對象。
我們想去旅行,但是沒有辦法提前去目的地訂酒店,所以我們通過同程藝龍來訂酒店。同程藝龍就是一個代理對象,他和酒店一樣,提供了訂酒店的方法。
我們沒有渠道去直接聯系房東,所以我們可以通過中介公司租房,房東把租房這件事委托給了中介公司,這里中介公司就是一個代理對象。代理對象除了調用真實對象的方法,還可以對方法進行增強。比如中介公司可以賺差價。
圖解:
這里可以看出,無論是代理對象和被代理對象,都實現了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
有沒有什么問題?
可以看出,我們在代理類中直接引用了被代理對象,所以代理類和被代理類是一種一對一的關系,即我們需要為每一個被代理類,創建一個代理類。
假設我們現在有一個打點的需求,要為系統中的一批對象增加記錄日志的方法,如果使用代理模式,就要為這一批對象創建代理類,這樣的工作量是無疑是巨大的。那么有沒有什么辦法可以讓我們可以少寫或者不寫代理類,卻能完成代理功能呢?這就要引出了我們要講的一個概念——動態代理(動態代理涉及到、反射類加載的一些知識,所以在下一篇文章中講解)
期待您的關注、推薦、收藏,同時也期待您的糾錯和批評。