提供對象的替代品或其佔位符。代理控制着對於原對象的訪問,容許在將請求提交給對象先後進行一些處理java
在面向對象的系統中,有些對象因爲某種緣由(好比對象建立的開銷很大,或者某些操做須要安全控制,或者須要進程外的訪問等),直接訪問對象會給使用者或者系統結構帶來不少麻煩 api
代理會將全部獲取了指向服務對象或其結果的客戶端記錄在案。代理會時不時地遍歷各個客戶端,檢查它們是否仍在運行。若是相應的客戶端列表爲空,代理就會銷燬該服務對象,釋放底層系統資源。代理還能夠記錄客戶端是否修改了服務對象。其餘客戶端還能夠複用未修改的對象緩存
1)能夠在客戶端毫無察覺的狀況下控制服務對象安全
2)客戶端對服務對象的生命週期沒有特殊要求, 你能夠對生命週期進行管理服務器
3)開閉原則。 你能夠在不對服務或客戶端作出修改的狀況下建立新代理網絡
4)Proxy模式能夠對用戶隱藏另外一種稱爲copy-on-write的優化方式,該優化與根據須要建立對象有關。拷貝一個龐大而複雜的對象是一種開銷很大的操做,若是這個拷貝並無被修改,那麼開銷就沒有必要。能夠用代理延遲這一拷貝過程。在實現copy-on-write時必須對實體進行引用計數。只有當用戶請求一個修改該實體的操做時,代理纔會真正的拷貝它。此時,代理須要減小實體引用計數,當引用數目爲零時,這個實體將被刪除app
5)服務響應可能會延遲 less
some_cool_media_library/ThirdPartyYouTubeLib.java: 遠程服務接口 dom
package proxy.some_cool_media_library; import java.util.HashMap; /** * @author GaoMing * @date 2021/7/20 - 19:25 */ public interface ThirdPartyYouTubeLib { HashMap<String, Video> popularVideos(); Video getVideo(String videoId); }
some_cool_media_library/ThirdPartyYouTubeClass.java: 遠程服務實現ide
package proxy.some_cool_media_library; import java.util.HashMap; /** * @author GaoMing * @date 2021/7/20 - 19:22 */ public class ThirdPartyYouTubeClass implements ThirdPartyYouTubeLib{ @Override public HashMap<String, Video> popularVideos() { connectToServer("http://www.youtube.com"); return getRandomVideos(); } @Override public Video getVideo(String videoId) { connectToServer("http://www.youtube.com/" + videoId); return getSomeVideo(videoId); } // ----------------------------------------------------------------------- // Fake methods to simulate network activity. They as slow as a real life. private int random(int min, int max) { return min + (int) (Math.random() * ((max - min) + 1)); } private void experienceNetworkLatency() { int randomLatency = random(5, 10); for (int i = 0; i < randomLatency; i++) { try { Thread.sleep(100); } catch (InterruptedException ex) { ex.printStackTrace(); } } } private void connectToServer(String server) { System.out.print("Connecting to " + server + "... "); experienceNetworkLatency(); System.out.print("Connected!" + "\n"); } private HashMap<String, Video> getRandomVideos() { System.out.print("Downloading populars... "); experienceNetworkLatency(); HashMap<String, Video> hmap = new HashMap<String, Video>(); hmap.put("catzzzzzzzzz", new Video("sadgahasgdas", "Catzzzz.avi")); hmap.put("mkafksangasj", new Video("mkafksangasj", "Dog play with ball.mp4")); hmap.put("dancesvideoo", new Video("asdfas3ffasd", "Dancing video.mpq")); hmap.put("dlsdk5jfslaf", new Video("dlsdk5jfslaf", "Barcelona vs RealM.mov")); hmap.put("3sdfgsd1j333", new Video("3sdfgsd1j333", "Programing lesson#1.avi")); System.out.print("Done!" + "\n"); return hmap; } private Video getSomeVideo(String videoId) { System.out.print("Downloading video... "); experienceNetworkLatency(); Video video = new Video(videoId, "Some video title"); System.out.print("Done!" + "\n"); return video; } }
some_cool_media_library/Video.java: 視頻文件
package proxy.some_cool_media_library; /** * @author GaoMing * @date 2021/7/20 - 19:22 */ public class Video { public String id; public String title; public String data; Video(String id, String title) { this.id = id; this.title = title; this.data = "Random video."; } }
proxy/YouTubeCacheProxy.java: 緩存代理
package proxy.proxy; import proxy.some_cool_media_library.ThirdPartyYouTubeClass; import proxy.some_cool_media_library.ThirdPartyYouTubeLib; import proxy.some_cool_media_library.Video; import java.util.HashMap; /** * @author GaoMing * @date 2021/7/20 - 19:23 */ public class YouTubeCacheProxy implements ThirdPartyYouTubeLib{ private ThirdPartyYouTubeLib youtubeService; private HashMap<String, Video> cachePopular = new HashMap<String, Video>(); private HashMap<String, Video> cacheAll = new HashMap<String, Video>(); public YouTubeCacheProxy() { this.youtubeService = new ThirdPartyYouTubeClass(); } @Override public HashMap<String, Video> popularVideos() { if (cachePopular.isEmpty()) { cachePopular = youtubeService.popularVideos(); } else { System.out.println("Retrieved list from cache."); } return cachePopular; } @Override public Video getVideo(String videoId) { Video video = cacheAll.get(videoId); if (video == null) { video = youtubeService.getVideo(videoId); cacheAll.put(videoId, video); } else { System.out.println("Retrieved video '" + videoId + "' from cache."); } return video; } public void reset() { cachePopular.clear(); cacheAll.clear(); } }
downloader/YouTubeDownloader.java: 媒體下載應用
package proxy.downloader; import proxy.some_cool_media_library.ThirdPartyYouTubeLib; import proxy.some_cool_media_library.Video; import java.util.HashMap; /** * @author GaoMing * @date 2021/7/20 - 19:23 */ public class YouTubeDownloader { private ThirdPartyYouTubeLib api; public YouTubeDownloader(ThirdPartyYouTubeLib api) { this.api = api; } public void renderVideoPage(String videoId) { Video video = api.getVideo(videoId); System.out.println("\n-------------------------------"); System.out.println("Video page (imagine fancy HTML)"); System.out.println("ID: " + video.id); System.out.println("Title: " + video.title); System.out.println("Video: " + video.data); System.out.println("-------------------------------\n"); } public void renderPopularVideos() { HashMap<String, Video> list = api.popularVideos(); System.out.println("\n-------------------------------"); System.out.println("Most popular videos on YouTube (imagine fancy HTML)"); for (Video video : list.values()) { System.out.println("ID: " + video.id + " / Title: " + video.title); } System.out.println("-------------------------------\n"); } }
Demo.java: 初始化代碼
package proxy; import proxy.downloader.YouTubeDownloader; import proxy.proxy.YouTubeCacheProxy; import proxy.some_cool_media_library.ThirdPartyYouTubeClass; /** * @author GaoMing * @date 2021/7/20 - 19:21 */ public class Demo { public static void main(String[] args) { YouTubeDownloader naiveDownloader = new YouTubeDownloader(new ThirdPartyYouTubeClass()); YouTubeDownloader smartDownloader = new YouTubeDownloader(new YouTubeCacheProxy()); long naive = test(naiveDownloader); long smart = test(smartDownloader); System.out.print("Time saved by caching proxy: " + (naive - smart) + "ms"); } private static long test(YouTubeDownloader downloader) { long startTime = System.currentTimeMillis(); // User behavior in our app: downloader.renderPopularVideos(); downloader.renderVideoPage("catzzzzzzzzz"); downloader.renderPopularVideos(); downloader.renderVideoPage("dancesvideoo"); // Users might visit the same page quite often. downloader.renderVideoPage("catzzzzzzzzz"); downloader.renderVideoPage("someothervid"); long estimatedTime = System.currentTimeMillis() - startTime; System.out.print("Time elapsed: " + estimatedTime + "ms\n"); return estimatedTime; } }
執行結果
Connecting to http://www.youtube.com... Connected! Downloading populars... Done! ------------------------------- Most popular videos on YouTube (imagine fancy HTML) ID: sadgahasgdas / Title: Catzzzz.avi ID: asdfas3ffasd / Title: Dancing video.mpq ID: 3sdfgsd1j333 / Title: Programing lesson#1.avi ID: mkafksangasj / Title: Dog play with ball.mp4 ID: dlsdk5jfslaf / Title: Barcelona vs RealM.mov ------------------------------- Connecting to http://www.youtube.com/catzzzzzzzzz... Connected! Downloading video... Done! ------------------------------- Video page (imagine fancy HTML) ID: catzzzzzzzzz Title: Some video title Video: Random video. ------------------------------- Connecting to http://www.youtube.com... Connected! Downloading populars... Done! ------------------------------- Most popular videos on YouTube (imagine fancy HTML) ID: sadgahasgdas / Title: Catzzzz.avi ID: asdfas3ffasd / Title: Dancing video.mpq ID: 3sdfgsd1j333 / Title: Programing lesson#1.avi ID: mkafksangasj / Title: Dog play with ball.mp4 ID: dlsdk5jfslaf / Title: Barcelona vs RealM.mov ------------------------------- Connecting to http://www.youtube.com/dancesvideoo... Connected! Downloading video... Done! ------------------------------- Video page (imagine fancy HTML) ID: dancesvideoo Title: Some video title Video: Random video. ------------------------------- Connecting to http://www.youtube.com/catzzzzzzzzz... Connected! Downloading video... Done! ------------------------------- Video page (imagine fancy HTML) ID: catzzzzzzzzz Title: Some video title Video: Random video. ------------------------------- Connecting to http://www.youtube.com/someothervid... Connected! Downloading video... Done! ------------------------------- Video page (imagine fancy HTML) ID: someothervid Title: Some video title Video: Random video. ------------------------------- Time elapsed: 9354ms Connecting to http://www.youtube.com... Connected! Downloading populars... Done! ------------------------------- Most popular videos on YouTube (imagine fancy HTML) ID: sadgahasgdas / Title: Catzzzz.avi ID: asdfas3ffasd / Title: Dancing video.mpq ID: 3sdfgsd1j333 / Title: Programing lesson#1.avi ID: mkafksangasj / Title: Dog play with ball.mp4 ID: dlsdk5jfslaf / Title: Barcelona vs RealM.mov ------------------------------- Connecting to http://www.youtube.com/catzzzzzzzzz... Connected! Downloading video... Done! ------------------------------- Video page (imagine fancy HTML) ID: catzzzzzzzzz Title: Some video title Video: Random video. ------------------------------- Retrieved list from cache. ------------------------------- Most popular videos on YouTube (imagine fancy HTML) ID: sadgahasgdas / Title: Catzzzz.avi ID: asdfas3ffasd / Title: Dancing video.mpq ID: 3sdfgsd1j333 / Title: Programing lesson#1.avi ID: mkafksangasj / Title: Dog play with ball.mp4 ID: dlsdk5jfslaf / Title: Barcelona vs RealM.mov ------------------------------- Connecting to http://www.youtube.com/dancesvideoo... Connected! Downloading video... Done! ------------------------------- Video page (imagine fancy HTML) ID: dancesvideoo Title: Some video title Video: Random video. ------------------------------- Retrieved video 'catzzzzzzzzz' from cache. ------------------------------- Video page (imagine fancy HTML) ID: catzzzzzzzzz Title: Some video title Video: Random video. ------------------------------- Connecting to http://www.youtube.com/someothervid... Connected! Downloading video... Done! ------------------------------- Video page (imagine fancy HTML) ID: someothervid Title: Some video title Video: Random video. ------------------------------- Time elapsed: 5875ms Time saved by caching proxy: 3479ms
java.lang.reflect.Proxy
識別方法:代理模式會將全部實際
工做委派給一些其餘對象。除非代理是某個服務的子類,不然每一個代理方法最後都應該引用一個服務對象