国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android設計模式之代理模式Proxy淺顯易懂的詳細說明

2019-10-22 18:14:12
字體:
來源:轉載
供稿:網友

一.概述

代理模式也是平時比較常用的設計模式之一,代理模式其實就是提供了一個新的對象,實現了對真實對象的操作,或成為真實對象的替身.在日常生活中也是很常見的.例如A要租房,為了省麻煩A會去找中介,中介會替代A去篩選房子,A坐享中介篩選的結果,并且交房租也是交給中介,這就是一個典型的日常生活中代理模式的應用.平時打開網頁,最先開到的一般都是文字,而圖片等一些大的資源都會延遲加載,這里也是使用了代理模式.

代理模式的組成

Abstract Subject:抽象主題-聲明真實主題和代理主題共同的接口

Real Subject:真實主題-真實的對象,需要被代理主題引用

Proxy Subject:代理主題-因為ProxySubject引用了RealSubject,并且實現了跟RealSubject一樣的接口,所以ProxySubject可以操作RealSubject,還可以提供一些附加操作,例如before & after

Android,設計模式,Proxy,代理模式

代理模式常用基于場景的分類

1.Virtual Proxy:

虛擬代理其實就是通過代理的模式對消耗資源比較大的對象做了一個延遲加載,就是什么時候用到這個對象才去創建它.

2.Remote Proxy:遠程代理是比較經典的應用了,類似于C/S模式(主要攔截并控制遠程方法的調用,做代理防火墻之類的).

3.Smart Reference Proxy:智能引用代理可以給引用的對象提供一些額外的操作,例如實現里面中介Searching和Prepare contract的動作.

4.Access Proxy;保護代理可以控制一個對象的訪問,必要時候提供一系列的權限管理.

5.Copy-on-write Proxy:寫時拷貝(克隆)代理其實是Virtual Proxy的分支,提供了拷貝大對象的時候只有在對象真正變化后才會進行拷貝(克隆)的操作(延遲拷貝).

代理模式的優缺點:

優點:

1.代理作為調用著和真實對象的中間層,降低了模塊間和系統的耦合性

2.可以以一個小對象代理一個大對象,達到優化系統提高運行速度的目的

3.提供RealSubject的權限管理

4.容易擴展,RealSubject和ProxySubject都接口化了,RealSubject更改業務后只要接口不變,ProxySubject可以不做任何修改.

缺點:

1.同優點1,因為調用者和真實對象多了一個中間層,所以會增加調用響應的時間

二.實現

這里就拿A找中介租房為Demo來構建代理模式.

1.普通代理

根據場景先定義一個抽象主題,IHouse,提供三個方法,分別是獲取房屋信息,簽合同和付租金.

/**  * Created by jesse on 15-7-24.  */ public interface IHouse {   void getHouseInfo();   void signContract();   void payFees(); } 

接下來定義真實主題,并實現IHouse接口.增加房屋名稱和價格兩個屬性,填充借口方法,在獲取房屋信息的時候就把房屋名稱和價格log出來;簽合同的時候log出簽合同的時間,付租金的時候log出價格.

public class House implements IHouse{   private final String TAG = House.class.getSimpleName();   private String name;   private double price;    public House(String name, double price){     this.name = name;     this.price = price;   }    @Override   public void getHouseInfo() {     Log.i(TAG, "House Info- name:" + name + " ¥:" + price);   }    @Override   public void signContract() {     Log.i(TAG, "Contract:" + name + " signed at" +         new SimpleDateFormat("HH:mm:ss").format(SystemClock.uptimeMillis()));   }    @Override   public void payFees() {     Log.i(TAG, "Bill: name-" + name + " $-" + price);   } } 

定義房屋代理,同樣需要實現IHouse接口,并持有House的引用.可以看到代理類其實就像有封裝House,提供了一些附加操作,例如客戶要看房子的時候代理會先檢索自己庫存的房屋信息,簽合同之前要準備合同之類的.

public class ProxyHouse implements IHouse{   private final String TAG = ProxyHouse.class.getSimpleName();   private IHouse house;   public ProxyHouse(IHouse house){     this.house = house;   }   @Override   public void getHouseInfo() {     Log.i(TAG, "searching");     house.getHouseInfo();     Log.i(TAG, "search finished");   }    @Override   public void signContract() {     Log.i(TAG, "prepare contract");     house.signContract();   }    @Override   public void payFees() {     house.payFees();   } } 

對于客戶來說,完全不用跟House進行直接交互,這里先定義一個房子叫唐頓莊園,租金5k,建立一個房屋代理,把唐頓莊園委托給代理.客戶要找房子,簽合同,付租金直接找代理就行了.

IHouse house = new House("Downton Abbey", 5000); IHouse proxyHouse = new ProxyHouse(house); Log.i(TAG, "looking for a perfect house"); proxyHouse.getHouseInfo(); Log.i(TAG, "thinking"); proxyHouse.signContract(); proxyHouse.payFees(); Log.i(TAG, "so easy");

Android,設計模式,Proxy,代理模式

整個代理模式的流程可以從下面的時序圖展示出來.Client只跟代理進行交互.

Android,設計模式,Proxy,代理模式

2.虛擬代理

虛擬代理前面有介紹,就是基于代理模式又做了延遲加載來節省內存,但是如果某個對象要在多個沒有固定時序地方使用的時候就要進行判空,也會一定程度上犧牲性能(有點像代理模式+懶漢模式).這里還是拿租房的例子來展示.

這里就假設House是一個很龐大的對象,在創建的時候很耗費資源,那我們就更改成當Custom需要用它的時候才去初始化.這里就在ProxyHouse構造的時候先判House的引用是否為空,然后才會初始化House,當然如果這里有多線程并發的話可以根據不同的場景進行加鎖或者雙檢鎖來保證線程安全.

public ProxyHouse(){   if (null == house)     house = new House("Downton Abbey", 5000); } [java] view plain copyIHouse proxyHouse = new ProxyHouse(); Log.i(TAG, "looking for a perfect house"); proxyHouse.getHouseInfo(); Log.i(TAG, "thinking"); proxyHouse.signContract(); proxyHouse.payFees(); Log.i(TAG, "so easy"); 

3.強制代理

強制代理是反其道而行之的代理模式,一般情況下代理模式都是通過代理來找到真實的對象,而強制代理則是通過真實對象才能找到代理也就是說由真實對象指定代理,當然最終訪問還是通過代理模式訪問的.從名字還能看出它跟其他代理的一個不同,就是強制用代理.拿上面普通代理的例子來說,Custom看不到實體的House的時候它只能通過代理來訪問,但是由于沒有限制,Custom也可以直接繞過ProxyHouse來訪問House,但是強制代理就多了一個限制,Custom必須通過ProxyHouse才能訪問House.就像一些房東嫌麻煩,有房客直接電話過來說要看房,房東給出一個中介的電話說你跟中介聯系吧.

首先需要在接口里面添加一個獲取代理的接口

public interface IHouse {   void getHouseInfo();   void signContract();   void payFees();   IHouse getProxy(); } 

真實對象實現接口,并在getProxy中實例化代理,同時在其他方法里面做代理判斷,只有使用自身自定的代理才會正常進行.

public class House implements IHouse{   private final String TAG = House.class.getSimpleName();   private String name;   private double price;   private IHouse proxy;    public House(String name, double price){     this.name = name;     this.price = price;   }    @Override   public void getHouseInfo() {     if (isProxy())       Log.i(TAG, "House Info- name:" + name + " ¥:" + price);     else       Log.i(TAG, "Please use correct proxy");   }    @Override   public void signContract() {     if (isProxy())       Log.i(TAG, "Contract:" + name + " signed at" +           new SimpleDateFormat("HH:mm:ss").format(SystemClock.uptimeMillis()));     else       Log.i(TAG, "Please use correct proxy");    }    @Override   public void payFees() {     if (isProxy())       Log.i(TAG, "Bill: name-" + name + " $-" + price);     else       Log.i(TAG, "Please use correct proxy");   }    @Override   public IHouse getProxy() {     if (null == proxy)       proxy = new ProxyHouse(this);     return proxy;   }    private boolean isProxy(){     if (null == proxy)       return false;     else       return true;   } } 

如果這個時候直接操作House對象,或者通過Custom構建的代理來訪問都會返回以下結果

Android,設計模式,Proxy,代理模式

所以我們必須使用由真實對象指定的代理才可以正常得訪問.

IHouse house = new House("Downton Abbey", 5000); house = house.getProxy(); Log.i(TAG, "looking for a perfect house"); house.getHouseInfo(); Log.i(TAG, "thinking"); house.signContract(); house.payFees(); 

但是這里的強制代理有個Bug,強制代理其實并沒有生效,Custom還是可以直接訪問House,例如我通過下面的方式來進行訪問,只是通過getProxy創建并獲取代理,但是我不用代理還是直接用House的實例進行訪問,這個時候還是可以正常訪問的.后續會想辦法解了這個Bug并且更新上來的.

IHouse house = new House("Downton Abbey", 5000); house.getProxy();//這里只是通過getProxy創建出代理 Log.i(TAG, "looking for a perfect house"); house.getHouseInfo(); Log.i(TAG, "thinking"); house.signContract(); house.payFees(); 

4.動態代理

上面介紹的都是自己先寫好的代理類,這樣代理關系都是固定的,當代理多個真實對象的時候就要寫多個代理類,并且會產生冗余的代碼,擴展性和可維護性都不高,而動態代理是基于反射實現了在程序運行的過程中才決定代理什么對象.像AOP的核心思想就是動態代理.(這里使用的是Java的動態代理)

既然是動態代理就不需要ProxyHouse也不需要實現IHouse接口了,這里寫一個ProxyHandler實現InvocationHandler的invoke接口,并且提供一個根據Proxy構建出來的代理實例給Custom.在通過反射調用真實對象具體的方法之前打印出該方法的名字.

public class ProxyHandler implements InvocationHandler{   private final String TAG = ProxyHandler.class.getSimpleName();   Object targetObj;    public Object newProxyInstance(Object targetObj){     this.targetObj = targetObj;     return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(),           targetObj.getClass().getInterfaces(), this);   }    @Override   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {     Object ret;     Log.i(TAG, "method name:" + method.getName());     ret = method.invoke(targetObj, args);     return ret;   } } 
ProxyHandler proxy = new ProxyHandler(); IHouse house = (IHouse) proxy.newProxyInstance(new House("Downton Abbey", 5000)); Log.i(TAG, "looking for a perfect house"); house.getHouseInfo(); Log.i(TAG, "thinking"); house.signContract(); house.payFees(); Log.i(TAG, "so easy"); 

從結果可以看出在真正invoke真實對象的方法之前都會打印出方法名,也可以在這里做一些其他的對象控制.

Android,設計模式,Proxy,代理模式

這個時候整個過程的時序圖就變成下面的樣子了,通過JDK的Proxy對象和反射的機制來支撐起來動態代理的核心功能.

Android,設計模式,Proxy,代理模式

三.總結

代理模式的使用場景還是挺多的,可以降低對象的復雜度,對項目進行解耦(特別是動態代理的AOP)等,學習設計模式其實最適合的方法就是拿來用,在適用于該模式的場景下靈活得去運用它才算是真正的掌握一種模式.


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 新沂市| 镇原县| 林口县| 石嘴山市| 宁海县| 磐安县| 二连浩特市| 宁南县| 宁武县| 海安县| 龙陵县| 龙江县| 保山市| 刚察县| 板桥市| 云霄县| 兴国县| 马山县| 内黄县| 南昌县| 岢岚县| 三原县| 柞水县| 始兴县| 宣化县| 永德县| 邹平县| 麟游县| 固镇县| 寿光市| 兴国县| 郓城县| 阳山县| 越西县| 昭觉县| 云安县| 西藏| 新余市| 吴旗县| 苏尼特左旗| 清涧县|