亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android設(shè)計模式之代理模式Proxy淺顯易懂的詳細(xì)說明

 更新時間:2018年03月15日 10:38:05   作者:Jesse-csdn  
Android設(shè)計模式之代理模式也是平時比較常用的設(shè)計模式之一,代理模式其實就是提供了一個新的對象,實現(xiàn)了對真實對象的操作,或成為真實對象的替身

一.概述

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

代理模式的組成

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

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

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

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

1.Virtual Proxy:

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

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

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

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

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

代理模式的優(yōu)缺點:

優(yōu)點:

1.代理作為調(diào)用著和真實對象的中間層,降低了模塊間和系統(tǒng)的耦合性

2.可以以一個小對象代理一個大對象,達到優(yōu)化系統(tǒng)提高運行速度的目的

3.提供RealSubject的權(quán)限管理

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

缺點:

1.同優(yōu)點1,因為調(diào)用者和真實對象多了一個中間層,所以會增加調(diào)用響應(yīng)的時間

二.實現(xiàn)

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

1.普通代理

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

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

接下來定義真實主題,并實現(xiàn)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); 
  } 
} 

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

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");

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

2.虛擬代理

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

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

public ProxyHouse(){ 
  if (null == house) 
    house = new House("Downton Abbey", 5000); 
} 
[java] view plain copy
IHouse 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.強制代理

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

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

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

真實對象實現(xiàn)接口,并在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構(gòu)建的代理來訪問都會返回以下結(jié)果

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

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創(chuàng)建并獲取代理,但是我不用代理還是直接用House的實例進行訪問,這個時候還是可以正常訪問的.后續(xù)會想辦法解了這個Bug并且更新上來的.

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

4.動態(tài)代理

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

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

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"); 

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

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

三.總結(jié)

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

相關(guān)文章

  • Android UI使用HTML布局方法實例

    Android UI使用HTML布局方法實例

    這篇文章主要介紹了Android UI使用HTML布局方法實例,布局文件直接用一個WebView來代替,這樣就可以在WebView中使用HTML布局了,需要的朋友可以參考下
    2015-05-05
  • Android SQLite數(shù)據(jù)庫操作代碼類分享

    Android SQLite數(shù)據(jù)庫操作代碼類分享

    這篇文章主要介紹了Android SQLite數(shù)據(jù)庫操作代碼類分享,本文直接給出實現(xiàn)代碼和使用代碼,需要的朋友可以參考下
    2015-03-03
  • Kotlin?select使用方法介紹

    Kotlin?select使用方法介紹

    select是Kotlin?1.6中的特性,即選擇最快的結(jié)果。select與async、Channel結(jié)合使用,可以大大提高程序的響應(yīng)速度,還可以提高程序的靈活性、擴展性
    2022-11-11
  • Android自定義ViewGroup(側(cè)滑菜單)詳解及簡單實例

    Android自定義ViewGroup(側(cè)滑菜單)詳解及簡單實例

    這篇文章主要介紹了Android自定義ViewGroup(側(cè)滑菜單)詳解及簡單實例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Android RecyclerView使用方法詳解

    Android RecyclerView使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Android RecyclerView的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Android系統(tǒng)開發(fā)中l(wèi)og的使用方法及簡單的原理

    Android系統(tǒng)開發(fā)中l(wèi)og的使用方法及簡單的原理

    LOG是廣泛使用的用來記錄程序執(zhí)行過程的機制,它既可以用于程序調(diào)試,也可以用于產(chǎn)品運營中的事件記錄;在平時開發(fā)過程中經(jīng)常需要與log打交道,所以很有必要了解log的使用方法及簡單的原理,感興趣的朋友可以了解下啊
    2013-01-01
  • android實現(xiàn)手機截屏并保存截圖功能

    android實現(xiàn)手機截屏并保存截圖功能

    這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)手機截屏并保存截圖功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Android開發(fā)之日歷CalendarView用法示例

    Android開發(fā)之日歷CalendarView用法示例

    這篇文章主要介紹了Android開發(fā)之日歷CalendarView用法,簡單分析了日歷CalendarView組件的功能、屬性設(shè)置方法、界面布局、事件監(jiān)聽等相關(guān)操作技巧,需要的朋友可以參考下
    2019-03-03
  • Android中AlertDilog顯示簡單和復(fù)雜列表的方法

    Android中AlertDilog顯示簡單和復(fù)雜列表的方法

    這篇文章主要介紹了Android中AlertDialog顯示簡單和復(fù)雜列表的方法,結(jié)合實例形式分析了Android的AlertDialog創(chuàng)建列表顯示對話框的相關(guān)方法與常見操作技巧,需要的朋友可以參考下
    2016-08-08
  • Android?資源加載使用偽代碼示例分析

    Android?資源加載使用偽代碼示例分析

    這篇文章主要為大家介紹了Android?資源加載使用偽代碼示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10

最新評論