前言
Android的設(shè)計模式系列文章介紹河哑,歡迎關(guān)注蜂林,持續(xù)更新中:
Android的設(shè)計模式-設(shè)計模式的六大原則
一句話總結(jié)23種設(shè)計模式則
創(chuàng)建型模式:
Android的設(shè)計模式-單例模式
Android的設(shè)計模式-建造者模式
Android的設(shè)計模式-工廠方法模式
Android的設(shè)計模式-簡單工廠模式
Android的設(shè)計模式-抽象工廠模式
Android的設(shè)計模式-原型模式
行為型模式:
Android的設(shè)計模式-策略模式
Android的設(shè)計模式-狀態(tài)模式
Android的設(shè)計模式-責(zé)任鏈模式
Android的設(shè)計模式-觀察者模式
Android的設(shè)計模式-模板方法模式
Android的設(shè)計模式-迭代器模式
Android的設(shè)計模式-備忘錄模式
Android的設(shè)計模式-訪問者模式
Android的設(shè)計模式-中介者模式
Android的設(shè)計模式-解釋器模式
Android的設(shè)計模式-命令模式
結(jié)構(gòu)型模式:
Android的設(shè)計模式-代理模式
Android的設(shè)計模式-組合模式
Android的設(shè)計模式-適配器模式
Android的設(shè)計模式-裝飾者模式
Android的設(shè)計模式-享元模式
Android的設(shè)計模式-外觀模式
Android的設(shè)計模式-橋接模式
1.定義
為其他對象提供一種代理以控制這個對象的訪問层扶。
2.介紹
- 代理模式屬于結(jié)構(gòu)型模式劣挫。
- 代理模式也叫委托模式橡淑。
- 生活中哼蛆,比如代購蕊梧、打官司等等,實際上都是一種代理模式腮介。
3.UML類圖
角色說明:
- Subject(抽象主題類):接口或者抽象類肥矢,聲明真實主題與代理的共同接口方法。
- RealSubject(真實主題類):也叫做被代理類或被委托類,定義了代理所表示的真實對象甘改,負(fù)責(zé)具體業(yè)務(wù)邏輯的執(zhí)行旅东,客戶端可以通過代理類間接的調(diào)用真實主題類的方法。
- Proxy(代理類):也叫委托類十艾,持有對真實主題類的引用抵代,在其所實現(xiàn)的接口方法中調(diào)用真實主題類中相應(yīng)的接口方法執(zhí)行。
- Client(客戶端類):使用代理模式的地方忘嫉。
4.實現(xiàn)
以海外代購為例荤牍,在國內(nèi)的人想買國外的東西只能去找國外的人去進行代購。
4.1 創(chuàng)建抽象主題類
人都是有購買這個方法的:
public interface People {
void buy();//購買
}
4.2 創(chuàng)建真實主題類
國內(nèi)的人想購買某些產(chǎn)品庆冕,定義具體的購買過程:
public class Domestic implements People {
@Override
public void buy() {//具體實現(xiàn)
System.out.println("國內(nèi)要買一個包");
}
}
4.3 創(chuàng)建代理類
海外的代購黨需要知道是誰(持有真實主題類的引用)想購買啥產(chǎn)品:
public class Oversea implements People {
People mPeople;//持有People類的引用
public Oversea(People people) {
mPeople = people;
}
@Override
public void buy() {
System.out.println("我是海外代購:");
mPeople.buy();//調(diào)用了被代理者的buy()方法,
}
}
4.5 客戶端測試:
public void test() {
People domestic = new Domestic(); //創(chuàng)建國內(nèi)購買人
People oversea = new Oversea(domestic); //創(chuàng)建海外代購類并將domestic作為構(gòu)造函數(shù)傳遞
oversea.buy(); //調(diào)用海外代購的buy()
}
輸出結(jié)果:
我是海外代購:
國內(nèi)要買一個包
5 靜態(tài)代理與動態(tài)代理
??從代碼的角度來分康吵,代理可以分為兩種:一種是靜態(tài)代理,另一種是動態(tài)代理访递。
??靜態(tài)代理就是在程序運行前就已經(jīng)存在代理類的字節(jié)碼文件晦嵌,代理類和委托類的關(guān)系在運行前就確定了。上面的例子實現(xiàn)就是靜態(tài)代理拷姿。
??動態(tài)代理類的源碼是在程序運行期間根據(jù)反射等機制動態(tài)的生成惭载,所以不存在代理類的字節(jié)碼文件。代理類和委托類的關(guān)系是在程序運行時確定响巢。
??下面我們實現(xiàn)動態(tài)代理描滔,Java提供了動態(tài)的代理接口InvocationHandler,實現(xiàn)該接口需要重寫invoke()方法:
5.1 創(chuàng)建動態(tài)代理類
public class DynamicProxy implements InvocationHandler {//實現(xiàn)InvocationHandler接口
private Object obj;//被代理的對象
public DynamicProxy(Object obj) {
this.obj = obj;
}
//重寫invoke()方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("海外動態(tài)代理調(diào)用方法: "+method.getName());
Object result = method.invoke(obj, args);//調(diào)用被代理的對象的方法
return result;
}
}
5.2 修改客戶端的測試方法:
public void test() {
People domestic = new Domestic(); //創(chuàng)建國內(nèi)購買人
DynamicProxy proxy = new DynamicProxy(domestic); //創(chuàng)建動態(tài)代理
ClassLoader classLoader = domestic.getClass().getClassLoader(); //獲取ClassLoader
People oversea = (People) Proxy.newProxyInstance(classLoader, new Class[]{People.class}, proxy); //通過 Proxy 創(chuàng)建海外代購實例 抵乓,實際上通過反射來實現(xiàn)的伴挚。
oversea.buy();//調(diào)用海外代購的buy()
}
輸出結(jié)果:
海外動態(tài)代理調(diào)用方法: buy
國內(nèi)要買一個包
5.3 靜態(tài)代理與動態(tài)代理比較
靜態(tài)代理的缺點:
- 靜態(tài)代理如果接口新增一個方法,除了所有實現(xiàn)類(真實主題類)需要實現(xiàn)這個方法外灾炭,所有代理類也需要實現(xiàn)此方法茎芋。增加了代碼維護的復(fù)雜度。
- 代理對象只服務(wù)于一種類型的對象蜈出,如果要服務(wù)多類型的對象田弥。必須要為每一種對象都進行代理,靜態(tài)代理在程序規(guī)模稍大時就無法勝任了铡原。
動態(tài)代理的優(yōu)點:
- 可以通過一個代理類完成全部的代理功能偷厦,接口中聲明的所有方法都被轉(zhuǎn)移到調(diào)用處理器一個集中的方法中處理(
InvocationHandler.invoke
)。當(dāng)接口方法數(shù)量較多時燕刻,我們可以進行靈活處理只泼,而不需要像靜態(tài)代理那樣每一個方法進行中轉(zhuǎn)。- 動態(tài)代理的應(yīng)用使我們的類職責(zé)更加單一卵洗,復(fù)用性更強请唱。
動態(tài)代理的缺點:
- 不能對類進行代理,只能對接口進行代理,如果我們的類沒有實現(xiàn)任何接口十绑,那么就不能使用這種方式進行動態(tài)代理(因為$Proxy()這個類集成了Proxy,Java的集成不允許出現(xiàn)多個父類)聚至。
6. 應(yīng)用場景
當(dāng)一個對象不能或者不想直接訪問另一個對象時,可以通過一個代理對象來間接訪問本橙。為保證客戶端使用的透明性扳躬,委托對象和代理對象要實現(xiàn)同樣的接口。
被訪問的對象不想暴露全部內(nèi)容時甚亭,可以通過代理去掉不想被訪問的內(nèi)容贷币。
-
根據(jù)適用范圍,代理模式可以分為以下幾種:
- 遠(yuǎn)程代理:為一個對象在不同的地址空間提供局部代表狂鞋,這樣系統(tǒng)可以將Server部分的事項隱藏片择。
- 虛擬代理:如果要創(chuàng)建一個資源消耗較大的對象,可以先用一個代理對象表示骚揍,在真正需要的時候才真正創(chuàng)建。
- 保護代理:用代理對象控制對一個對象的訪問啰挪,給不同的用戶提供不同的訪問權(quán)限信不。
- 智能引用:在引用原始對象的時候附加額外操作,并對指向原始對象的引用增加引用計數(shù)亡呵。
7. 優(yōu)點
- 代理作為調(diào)用者和真實主題的中間層,降低了模塊間和系統(tǒng)的耦合性抽活。
- 可以以一個小對象代理一個大對象,達到優(yōu)化系統(tǒng)提高運行速度的目的。
- 代理對象能夠控制調(diào)用者的訪問權(quán)限锰什,起到了保護真實主題的作用下硕。
8. 缺點
- 由于在調(diào)用者和真實主題之間增加了代理對象,因此可能會造成請求的處理速度變慢汁胆。
- 實現(xiàn)代理模式需要額外的工作(有些代理模式的實現(xiàn)非常復(fù)雜)梭姓,從而增加了系統(tǒng)實現(xiàn)的復(fù)雜度。
9. Android中的源碼分析
Android的源碼中多個地方都用到代理模式嫩码,比如ActivityManagerProxy
這個代理類誉尖。鑒于ActivityManager
的代碼非常復(fù)雜,這里就不進行分析了铸题,后面會另開文章進行具體分析铡恕,這里主要對ActivityManager
中的代理模式進行簡單的分析一下。先看下相關(guān)類的結(jié)構(gòu)圖:
??由上圖可以看到:ActivityManagerProxy
和ActivityManagerNative
都是實現(xiàn)IActivityManager
這個接口丢间,IActivityManager
就是抽象主題了探熔,ActivityManagerProxy
一看就是代理類,而真實主題則是ActivityManagerNative
烘挫,實際上ActivityManagerNative
是個抽象類诀艰,真正的具體實現(xiàn)是在它的子類ActivityManagerService
中。
??這里的代理實質(zhì)是個遠(yuǎn)程代理,ActivityManagerProxy
與ActivityManagerService
是運行在不同的進程空間中的涡驮。
??關(guān)于代理模式的分析就到這里為止了暗甥,其他的東西就不分析了。
相關(guān)文章閱讀
Android的設(shè)計模式-設(shè)計模式的六大原則
一句話總結(jié)23種設(shè)計模式則
創(chuàng)建型模式:
Android的設(shè)計模式-單例模式
Android的設(shè)計模式-建造者模式
Android的設(shè)計模式-工廠方法模式
Android的設(shè)計模式-簡單工廠模式
Android的設(shè)計模式-抽象工廠模式
Android的設(shè)計模式-原型模式
行為型模式:
Android的設(shè)計模式-策略模式
Android的設(shè)計模式-狀態(tài)模式
Android的設(shè)計模式-責(zé)任鏈模式
Android的設(shè)計模式-觀察者模式
Android的設(shè)計模式-模板方法模式
Android的設(shè)計模式-迭代器模式
Android的設(shè)計模式-備忘錄模式
Android的設(shè)計模式-訪問者模式
Android的設(shè)計模式-中介者模式
Android的設(shè)計模式-解釋器模式
Android的設(shè)計模式-命令模式
結(jié)構(gòu)型模式:
Android的設(shè)計模式-代理模式
Android的設(shè)計模式-組合模式
Android的設(shè)計模式-適配器模式
Android的設(shè)計模式-裝飾者模式
Android的設(shè)計模式-享元模式
Android的設(shè)計模式-外觀模式
Android的設(shè)計模式-橋接模式