定義:爲其餘對象提供一種代理以控制對這個對象的訪問。在某些狀況下,一個對象不適合或者不能直接引用另外一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用。一個類表明另外一個類的功能。這種類型的設計模式屬於結構型模式。java
意圖:爲其餘對象提供一種代理以控制對這個對象的訪問。spring
主要解決:在直接訪問對象時帶來的問題,好比說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象因爲某些緣由(好比對象建立開銷很大,或者某些操做須要安全控制,或者須要進程外的訪問),直接訪問會給使用者或者系統結構帶來不少麻煩,咱們能夠在訪問此對象時加上一個對此對象的訪問層。設計模式
應用實例:一、Windows 裏面的快捷方式。二、買火車票不必定在火車站買,也能夠去代售點。 三、spring aop。安全
優勢: 一、職責清晰。ide
被代理對象只負責本身實際的業務邏輯,不關心其餘非自己的職責。並將其餘事務能夠經過代理類處理。測試
二、高擴展性。this
不管被代理對象如何改變,只要代理類和被代理類都實現了統一接口,都不一樣修改代理類,並且即便擴展了新的被代理類,代理類也可使用,只要建立代理類的時候傳入對應的被代理類對象。spa
三、智能化。設計
這主要體如今動態代理中,下面會講解動態代理。若是有興趣瞭解Spring的AOP,其實就是使用了動態代理。3d
缺點: 一、因爲在客戶端和真實主題之間增長了代理對象,所以有些類型的代理模式可能會形成請求的處理速度變慢。
二、實現代理模式須要額外的工做,有些代理模式的實現很是複雜。
注意事項: 一、和適配器模式的區別:適配器模式主要改變所考慮對象的接口,而代理模式不能改變所代理類的接口。
二、和裝飾器模式的區別:裝飾器模式爲了加強功能,而代理模式是爲了加以控制。
咱們舉個示例,好比在娛樂圈,客戶與藝人進行商業合做,通常都不是與藝人直接聯繫,簽定時間、地點、薪酬等合同,而是
找藝人的經紀人商討,那麼這裏商藝活動就是抽象對象(主題),藝人就被代理對象,經紀人就是代理對象。
代碼示例:
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()獲取代理來訪問真實角色的全部方法,它根本就不須要產生一個代理角色,代理的管理已經由真實角色本身來完成。
後續講解一個 虛擬代理模式 和動態代理模式。