Android常見設(shè)計模式十四:門面模式

對于開發(fā)人員來說靴拱,設(shè)計模式有時候就是一道坎褥芒,但是設(shè)計模式又非常有用嚼松,過了這道坎嫡良,它可以讓你水平提高一個檔次。而在android開發(fā)中献酗,必要的了解一些設(shè)計模式又是必須的寝受,因為設(shè)計模式在Android源碼中,可以說是無處不在罕偎。對于想系統(tǒng)的學(xué)習(xí)設(shè)計模式的同學(xué)很澄,這里推薦一本書,《大話設(shè)計模式》颜及。


Android常用設(shè)計模式系列:

面向?qū)ο蟮幕A(chǔ)特征
面向?qū)ο蟮脑O(shè)計原則
單例模式
模板模式
適配器模式
工廠模式
代理模式
原型模式
策略模式
Build模式
觀察者模式
裝飾者模式
中介模式
門面模式


一甩苛、門面模式

門面模式是對象的結(jié)構(gòu)模式,外部與一個子系統(tǒng)的通信必須通過一個統(tǒng)一的門面對象進(jìn)行俏站。門面模式提供一個高層次的接口讯蒲,使得子系統(tǒng)更易于使用。

醫(yī)院的例子

現(xiàn)代的軟件系統(tǒng)都是比較復(fù)雜的肄扎,設(shè)計師處理復(fù)雜系統(tǒng)的一個常見方法便是將其“分而治之”爱葵,把一個系統(tǒng)劃分為幾個較小的子系統(tǒng)。如果把醫(yī)院作為一個子系統(tǒng)反浓,按照部門職能萌丈,這個系統(tǒng)可以劃分為掛號、門診雷则、劃價辆雾、化驗、收費月劈、取藥等度迂。看病的病人要與這些部門打交道猜揪,就如同一個子系統(tǒng)的客戶端與一個子系統(tǒng)的各個類打交道一樣惭墓,不是一件容易的事情。

首先病人必須先掛號而姐,然后門診腊凶。如果醫(yī)生要求化驗,病人必須首先劃價拴念,然后繳費钧萍,才可以到化驗部門做化驗≌螅化驗后再回到門診室风瘦。

image.png

上圖描述的是病人在醫(yī)院里的體驗,圖中的方框代表醫(yī)院公般。

解決這種不便的方法便是引進(jìn)門面模式万搔,醫(yī)院可以設(shè)置一個接待員的位置胡桨,由接待員負(fù)責(zé)代為掛號、劃價瞬雹、繳費昧谊、取藥等。這個接待員就是門面模式的體現(xiàn)挖炬,病人只接觸接待員揽浙,由接待員與各個部門打交道状婶。

image.png

二意敛、門面模式的結(jié)構(gòu)

門面模式?jīng)]有一個一般化的類圖描述,最好的描述方法實際上就是以一個例子說明膛虫。

image.png

由于門面模式的結(jié)構(gòu)圖過于抽象草姻,因此把它稍稍具體點。假設(shè)子系統(tǒng)內(nèi)有三個模塊稍刀,分別是ModuleA撩独、ModuleB和ModuleC,它們分別有一個示例方法账月,那么此時示例的整體結(jié)構(gòu)圖如下:

image.png

在這個對象圖中综膀,出現(xiàn)了兩個角色:

●  門面(Facade)角色 :客戶端可以調(diào)用這個角色的方法。此角色知曉相關(guān)的(一個或者多個)子系統(tǒng)的功能和責(zé)任局齿。在正常情況下剧劝,本角色會將所有從客戶端發(fā)來的請求委派到相應(yīng)的子系統(tǒng)去。

●  子系統(tǒng)(SubSystem)角色 :可以同時有一個或者多個子系統(tǒng)抓歼。每個子系統(tǒng)都不是一個單獨的類讥此,而是一個類的集合(如上面的子系統(tǒng)就是由ModuleA、ModuleB谣妻、ModuleC三個類組合而成)萄喳。每個子系統(tǒng)都可以被客戶端直接調(diào)用,或者被門面角色調(diào)用蹋半。子系統(tǒng)并不知道門面的存在他巨,對于子系統(tǒng)而言,門面僅僅是另外一個客戶端而已减江。

也就是說闻蛀,本來應(yīng)該客戶端來跟各個子系統(tǒng)來接觸,但是有了門面模式之后您市,客戶端有什么操作只需要跟門面來打交道觉痛,告訴門面類,下面的事情就交給門面來協(xié)調(diào)組織子系統(tǒng)來做茵休。

使用門面模式:


不使用門面模式:

三薪棒、門面模式的實現(xiàn)

使用門面模式還有一個附帶的好處手蝎,就是能夠有選擇性地暴露方法。一個模塊中定義的方法可以分成兩部分俐芯,一部分是給子系統(tǒng)外部使用的棵介,一部分是子系統(tǒng)內(nèi)部模塊之間相互調(diào)用時使用的。有了Facade類吧史,那么用于子系統(tǒng)內(nèi)部模塊之間相互調(diào)用的方法就不用暴露給子系統(tǒng)外部了邮辽。

比如,定義如下A贸营、B吨述、C模塊。

public class Module { /** * 提供給子系統(tǒng)外部使用的方法 */
    public void a1(){}; /** * 子系統(tǒng)內(nèi)部模塊之間相互調(diào)用時使用的方法 */
    public void a2(){}; 
    public void a3(){};
}
public class ModuleB { /** * 提供給子系統(tǒng)外部使用的方法 */
    public void b1(){}; /** * 子系統(tǒng)內(nèi)部模塊之間相互調(diào)用時使用的方法 */
    public void b2(){}; 
    public void b3(){};
}
public class ModuleC { /** * 提供給子系統(tǒng)外部使用的方法 */
    public void c1(){}; /** * 子系統(tǒng)內(nèi)部模塊之間相互調(diào)用時使用的方法 */
    public void c2(){}; 
    public void c3(){};
}
public class ModuleFacade {

    ModuleA a = new ModuleA();
    ModuleB b = new ModuleB();
    ModuleC c = new ModuleC(); /** * 下面這些是A钞脂、B揣云、C模塊對子系統(tǒng)外部提供的方法 */
    
    public void a1(){
        a.a1();
    } 

    public void b1(){
        b.b1();
    } 

    public void c1(){
        c.c1();
    }
}

這樣定義一個ModuleFacade類可以有效地屏蔽內(nèi)部的細(xì)節(jié),免得客戶端去調(diào)用Module類時冰啃,發(fā)現(xiàn)一些不需要它知道的方法邓夕。比如a2()和a3()方法就不需要讓客戶端知道,否則既暴露了內(nèi)部的細(xì)節(jié)阎毅,又讓客戶端迷惑焚刚。對客戶端來說,他可能還要去思考a2()扇调、a3()方法用來干什么呢矿咕?其實a2()和a3()方法是內(nèi)部模塊之間交互的,原本就不是對子系統(tǒng)外部的肃拜,所以干脆就不要讓客戶端知道痴腌。

初學(xué)者往往以為通過繼承一個門面類便可在子系統(tǒng)中加入新的行為,這是錯誤的燃领。門面模式的用意是為子系統(tǒng)提供一個集中化和簡化的溝通管道士聪,而不能向子系統(tǒng)加入新的行為。比如醫(yī)院中的接待員并不是醫(yī)護(hù)人員猛蔽,接待員并不能為病人提供醫(yī)療服務(wù)剥悟。

四、模式應(yīng)用講解

1曼库、門面模式在Tomcat中的使用

Tomcat中門面模式使用的很多区岗,因為Tomcat中有很多不同組件,每個組件要相互通信毁枯,但是又不能將自己內(nèi)部數(shù)據(jù)過多的暴露給其他組件慈缔。用門面模式隔離數(shù)據(jù)是個很好的方法。

下面是Request上使用的門面模式:

image.png

使用過Servlet的人都清楚种玛,除了要在web.xml做相應(yīng)的配置外藐鹤,還需繼承一個叫HttpServlet的抽象類瓤檐,并且重寫doGet與doPost方法(當(dāng)然只重寫service方法也是可以的)。

public class TestServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response);

    } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

}

可以看出doGet與doPost方法有兩個參數(shù)娱节,參數(shù)類型是接口HttpServletRequest與接口HttpServletResponse挠蛉,那么從Tomcat中傳遞過來的真實類型到底是什么呢?通過debug會發(fā)現(xiàn)肄满,在真正調(diào)用TestServlet類之前谴古,會經(jīng)過很多Tomcat中的方法。如下圖所示

image.png

注意紅色方框圈中的類稠歉,StandardWrapperValue類中的invoke方法225行代碼如下:

filterChain.doFilter(request.getRequest(), response.getResponse());

在StandardWrapperValue類中并沒有直接將Request對象與Response對象傳遞給ApplicationFilterChain類的doFilter方法掰担,傳遞的是RequestFacade與ResponseFacade對象,為什么這么說呢轧抗,看一下request.getRequest()與response.getResponse()方法就真相大白了恩敌。

Request類

public HttpServletRequest getRequest() { if (facade == null) {
            facade = new RequestFacade(this);
        } return facade;
    }

Response類

public HttpServletResponse getResponse() { if (facade == null) {
            facade = new ResponseFacade(this);
        } return (facade);
    }

可以看到它們返回都是各自的一個門面類瞬测,那么這樣做有什么好處呢横媚?

Request對象中的很多方法都是內(nèi)部組件之間相互交互時使用的,比如setComet月趟、setRequestedSessionId等方法(這里就不一一列舉了)灯蝴。這些方法并不對外部公開,但是又必須設(shè)置為public孝宗,因為還需要跟內(nèi)部組件之間交互使用穷躁。最好的解決方法就是通過使用一個Facade類,將與內(nèi)部組件之間交互使用的方法屏蔽掉因妇,只提供給外部程序感興趣的方法问潭。

如果不使用Facade類,直接傳遞的是Request對象和Response對象婚被,那么熟悉容器內(nèi)部運作的程序員可以分別把ServletRequest和ServletResponse對象向下轉(zhuǎn)換為Request和Response狡忙,并調(diào)用它們的公共方法。比如擁有Request對象址芯,就可以調(diào)用setComet灾茁、setRequestedSessionId等方法,這會危害安全性谷炸。

2北专、Android中的門面模式

Context是最重要的一個類型。它封裝了很多重要的操作旬陡,比如startActivity()拓颓、sendBroadcast()等,幾乎是開發(fā)者對應(yīng)用操作的統(tǒng)一入口描孟。Context是一個抽象類驶睦,它只是定義了抽象接口腻格,真正的實現(xiàn)在ContextImpl類中。它就類似于門面類啥繁。

另外在Android里面我們往往會寫各種各樣的工具來菜职,這些工具類可以幫我們完成各種各樣的操作或者幫我們獲取到各種各樣的信息,它也相當(dāng)于一個門面類旗闽,使用了門面模式酬核,我們需要什么操作直接調(diào)用就可以,它屏蔽了底層的實現(xiàn)适室。

五嫡意、門面模式的優(yōu)缺點

優(yōu)點:

  • 松散耦合
    減少系統(tǒng)的相互依賴,上面也提到不使用門面模式捣辆,外界訪問直接深入到子系統(tǒng)內(nèi)部蔬螟,相互之間是一種強(qiáng)耦合關(guān)系這樣的強(qiáng)依賴是系統(tǒng)設(shè)計所不能接受的,門面模式的出現(xiàn)就很好地解決了該問題汽畴,所有的依賴都是對門面對象的依賴旧巾,與子系統(tǒng)無關(guān)。

  • 簡單易用
    門面模式讓子系統(tǒng)更加易用忍些,客戶端不再需要了解子系統(tǒng)內(nèi)部的實現(xiàn)鲁猩,也不需要跟眾多子系統(tǒng)內(nèi)部的模塊進(jìn)行交互,只需要跟門面類交互就可以了罢坝。

  • 更好的劃分訪問層次
    通過合理使用Facade廓握,可以幫助我們更好地劃分訪問的層次。有些方法是對系統(tǒng)外的嘁酿,有些方法是系統(tǒng)內(nèi)部使用的隙券。把需要暴露給外部的功能集中到門面中,這樣既方便客戶端使用闹司,也很好地隱藏了內(nèi)部的細(xì)節(jié)娱仔。

  • 提高安全性
    訪問子系統(tǒng)的哪些業(yè)務(wù)就開通哪些邏輯,不需要把子系統(tǒng)的內(nèi)部方法直接暴露給外部調(diào)用开仰。

缺點

  • 門面模式最大的缺點就是不符合開閉原則拟枚,對修改關(guān)閉,對擴(kuò)展開放众弓。

  • 系統(tǒng)投產(chǎn)后發(fā)現(xiàn)問題唯一能做的一件事就是修改門面角色的代碼恩溅,這個風(fēng)險相當(dāng)大。

六 結(jié)語

門面模式是一個很好的封裝方法谓娃,一個子系統(tǒng)比較復(fù)雜時脚乡,比如算法或者業(yè)務(wù)比較復(fù)雜,就可以封裝出一個或多個門面出來,項目的結(jié)構(gòu)簡單奶稠,而且擴(kuò)展性非常好俯艰。還有,對于一個較大項目锌订,為了避免人員帶來的風(fēng)險竹握,也可以使用門面模式。

門面模式和 中介模式

  • 1辆飘、從定義上啦辐,門面模式為復(fù)雜的子系統(tǒng)提供一個統(tǒng)一的訪問界面,它定義的是一個高層接口蜈项,該接口使得子系統(tǒng)更加容易使用芹关,避免外部模塊深入到子系統(tǒng)內(nèi)部而產(chǎn)生與子系統(tǒng)內(nèi)部細(xì)節(jié)耦合的問題。中介者模式使用一個中介對象來封裝一系列同事對象的交互行為紧卒,它使各對象之間不再顯式地引用侥衬,從而使其耦合松散,建立一個可擴(kuò)展的應(yīng)用架構(gòu)跑芳。

  • 2轴总、從功能上,門面模式只是增加了一個門面聋亡,它對子系統(tǒng)來說沒有增加任何的功能肘习,子系統(tǒng)若脫離門面模式是完全可以獨立運行的际乘。而中介者模式則增加了業(yè)務(wù)功能坡倔,它把各個同事類中的原有耦合關(guān)系移植到了中介者,同事類不可能脫離中介者而獨立存在脖含。

  • 3罪塔、從關(guān)系上,對門面模式來說养葵,子系統(tǒng)不知道有門面存在征堪,而對中介者來說,每個同事類都知道中介者存在关拒,因為要依靠中介者調(diào)和同事之間的關(guān)系佃蚜,它們對中介者非常了解。

  • 4着绊、從封裝程度上谐算,門面模式是一種簡單的封裝,所有的請求處理都委托給子系統(tǒng)完成归露,而中介者模式則需要有一個中心洲脂,由中心協(xié)調(diào)同事類完成,并且中心本身也完成部分業(yè)務(wù)剧包,它屬于更進(jìn)一步的業(yè)務(wù)功能封裝恐锦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末往果,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子一铅,更是在濱河造成了極大的恐慌陕贮,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件潘飘,死亡現(xiàn)場離奇詭異飘蚯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)福也,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門局骤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人暴凑,你說我怎么就攤上這事峦甩。” “怎么了现喳?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵凯傲,是天一觀的道長。 經(jīng)常有香客問我嗦篱,道長冰单,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任灸促,我火速辦了婚禮诫欠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浴栽。我一直安慰自己荒叼,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布典鸡。 她就那樣靜靜地躺著被廓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪萝玷。 梳的紋絲不亂的頭發(fā)上嫁乘,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機(jī)與錄音球碉,去河邊找鬼蜓斧。 笑死,一個胖子當(dāng)著我的面吹牛汁尺,可吹牛的內(nèi)容都是我干的法精。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼搂蜓!你這毒婦竟也來了狼荞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤帮碰,失蹤者是張志新(化名)和其女友劉穎相味,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體殉挽,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡丰涉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了斯碌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片一死。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖傻唾,靈堂內(nèi)的尸體忽然破棺而出投慈,到底是詐尸還是另有隱情,我是刑警寧澤冠骄,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布伪煤,位于F島的核電站,受9級特大地震影響凛辣,放射性物質(zhì)發(fā)生泄漏抱既。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一扁誓、第九天 我趴在偏房一處隱蔽的房頂上張望防泵。 院中可真熱鬧,春花似錦跋理、人聲如沸择克。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壹堰,卻和暖如春拭卿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贱纠。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工峻厚, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谆焊。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓惠桃,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辜王,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 《三國演義》中有曰:劉備劈狐、諸葛亮趁曹操赤壁之戰(zhàn)失利,大肆擴(kuò)充地盤呐馆,先后占領(lǐng)荊州大部地區(qū)肥缔,引起東吳孫權(quán)的警惕。為了限...
    YoungManSter閱讀 1,154評論 2 4
  • 定義 門面模式是對象的結(jié)構(gòu)模式汹来,外部與一個子系統(tǒng)的通信必須通過一個統(tǒng)一的門面對象進(jìn)行续膳。門面模式提供一個高層次的接口...
    步積閱讀 2,213評論 0 3
  • 門面模式本質(zhì)上就是化零為整;引入一個中介類收班,把各個分散的功能組合成一個整體坟岔,只對外暴露一個統(tǒng)一的接口。門面模式實現(xiàn)...
    小胖學(xué)編程閱讀 676評論 0 2
  • 簡介 項目開發(fā)中發(fā)現(xiàn)問題摔桦、解決問題這個過程中會出現(xiàn)很多問題炮车,比如重復(fù)出現(xiàn)、某個問題的遺留酣溃,這些問題的本質(zhì)就是設(shè)計模...
    零寬度接合閱讀 230評論 0 0
  • 6.24起瘦穆,本來以為今天早起要失敗了,但被胃給叫醒了赊豌!頭疼好了扛或,去走路去!
    池淺笑安然閱讀 144評論 0 0