Android的設(shè)計(jì)模式-模板方法模式

前言

Android的設(shè)計(jì)模式系列文章介紹座柱,歡迎關(guān)注,持續(xù)更新中:

Android的設(shè)計(jì)模式-設(shè)計(jì)模式的六大原則
一句話總結(jié)23種設(shè)計(jì)模式則
創(chuàng)建型模式:
Android的設(shè)計(jì)模式-單例模式
Android的設(shè)計(jì)模式-建造者模式
Android的設(shè)計(jì)模式-工廠方法模式
Android的設(shè)計(jì)模式-簡單工廠模式
Android的設(shè)計(jì)模式-抽象工廠模式
Android的設(shè)計(jì)模式-原型模式
行為型模式:
Android的設(shè)計(jì)模式-策略模式
Android的設(shè)計(jì)模式-狀態(tài)模式
Android的設(shè)計(jì)模式-責(zé)任鏈模式
Android的設(shè)計(jì)模式-觀察者模式
Android的設(shè)計(jì)模式-模板方法模式
Android的設(shè)計(jì)模式-迭代器模式
Android的設(shè)計(jì)模式-備忘錄模式
Android的設(shè)計(jì)模式-訪問者模式
Android的設(shè)計(jì)模式-中介者模式
Android的設(shè)計(jì)模式-解釋器模式
Android的設(shè)計(jì)模式-命令模式
結(jié)構(gòu)型模式:
Android的設(shè)計(jì)模式-代理模式
Android的設(shè)計(jì)模式-組合模式
Android的設(shè)計(jì)模式-適配器模式
Android的設(shè)計(jì)模式-裝飾者模式
Android的設(shè)計(jì)模式-享元模式
Android的設(shè)計(jì)模式-外觀模式
Android的設(shè)計(jì)模式-橋接模式

1.定義

定義一個(gè)操作中的算法框架迹鹅,而將一些步驟延遲到子類中,使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義算法的某些特定步驟贞言。

2.介紹

  • 模板方法模式屬于行為型模式斜棚。
  • 模板方法模式主要是用來定義一套流程下來的固定步驟,而具體的步驟實(shí)現(xiàn)則可以是不固定的。

3.UML類圖

模板方法UML類圖.jpg
角色說明:

AbstractClass(抽象類):弟蚀,定義了一整套算法框架蚤霞。
ConcreteClass(具體實(shí)現(xiàn)類):具體實(shí)現(xiàn)類,根據(jù)需要去實(shí)現(xiàn)抽象類中的方法粗梭。

4.實(shí)現(xiàn)

繼續(xù)以送快遞為例争便,快遞員送快遞基本就是一套固定的流程:收到快遞,準(zhǔn)備派送->聯(lián)系收貨人->確定結(jié)果断医。

4.1 創(chuàng)建抽象類

定義算法框架滞乙,這里是快遞員派送快遞的步驟:

    public abstract class Postman {//抽象快遞員類

        //派送流程
        public final void post() {//這里申明為final,不希望子類覆蓋這個(gè)方法鉴嗤,防止更改流程的執(zhí)行順序
            prepare();//準(zhǔn)備派送
            call();//聯(lián)系收貨人
            if (isSign())//是否簽收
                sign();//簽收
            else refuse();//拒簽
        }

        protected void prepare() {//準(zhǔn)備操作斩启,固定流程,父類實(shí)現(xiàn)
            System.out.println("快遞已達(dá)到醉锅,準(zhǔn)備派送");
        }

        protected abstract void call();//聯(lián)系收貨人兔簇,聯(lián)系人不一樣,所以為抽象方法硬耍,子類實(shí)現(xiàn)

        protected boolean isSign() {//是否簽收,這個(gè)是鉤子方法垄琐,用來控制流程的走向
            return true;
        }

        protected void sign() {//簽收,這個(gè)是固定流程经柴,父類實(shí)現(xiàn)
            System.out.println("客戶已簽收狸窘,上報(bào)系統(tǒng)");
        }

        protected void refuse() {//拒簽,空實(shí)現(xiàn)坯认,這個(gè)也是鉤子方法翻擒,子類可以跟進(jìn)實(shí)際來決定是否去實(shí)現(xiàn)這個(gè)方法
        }
    }

需要注意的是上面的抽象類(Postman)包含了三種類型的方法:抽象方法、具體方法和鉤子方法牛哺。

  • 抽象方法:需要子類去實(shí)現(xiàn)陋气。如上面的call()
  • 具體方法:抽象父類中直接實(shí)現(xiàn)引润。如上面的prepare()sign()巩趁。
  • 鉤子方法:有兩種,第一種椰拒,它是一個(gè)空實(shí)現(xiàn)的方法晶渠,子類可以視情況來決定是否要覆蓋它,如上面的refuse()燃观;第二種褒脯,它的返回類型通常是boolean類型的,一般用于對(duì)某個(gè)條件進(jìn)行判斷缆毁,如果條件滿足則執(zhí)行某一步驟番川,否則將不執(zhí)行,如上面的isSign()
4.2 創(chuàng)建具體實(shí)現(xiàn)類

根據(jù)需要去實(shí)現(xiàn)抽象類中的方法颁督,下面以派送給兩個(gè)不同的人為例践啄,其中一個(gè)簽收,另一個(gè)拒收:

    public class PostA extends Postman {//派送給A先生

        @Override
        protected void call() {//聯(lián)系收貨沉御,實(shí)現(xiàn)父類的抽象方法
            System.out.println("聯(lián)系A(chǔ)先生并送到門口");
        }
    }

    public class PostB extends Postman {//派送給B先生

        @Override
        protected void call() {//聯(lián)系收貨屿讽,實(shí)現(xiàn)父類的抽象方法
            System.out.println("聯(lián)系B先生并送到門口");
        }

        @Override
        protected boolean isSign() {//是否簽收,覆蓋父類的鉤子方法,控制流程的走向
            return false;
        }

        @Override
        protected void refuse() {//拒簽吠裆,覆蓋父類的鉤子方法
            System.out.println("拒絕簽收:商品不符");
        }
    }
4.3 客戶端測(cè)試
    public void test(){
        System.out.println("----派送A----");
        Postman postA=new PostA();
        postA.post();
        System.out.println("----派送B----");
        Postman postB=new PostB();
        postB.post();
    }
輸出結(jié)果:
----派送A----
快遞已達(dá)到伐谈,準(zhǔn)備派送
聯(lián)系A(chǔ)先生并送到門口
客戶已簽收,上報(bào)系統(tǒng)
----派送B----
快遞已達(dá)到试疙,準(zhǔn)備派送
聯(lián)系B先生并送到門口
拒絕簽收:商品不符

5. 應(yīng)用場(chǎng)景

  • 一次性實(shí)現(xiàn)算法的執(zhí)行順序和固定不變部分诵棵,可變部分則交由子類來實(shí)現(xiàn)。
  • 多個(gè)子類中擁有相同的行為時(shí)祝旷,可以將其抽取出來放在父類中履澳,避免重復(fù)的代碼。
  • 使用鉤子方法來讓子類決定父類的某個(gè)步驟是否執(zhí)行怀跛,實(shí)現(xiàn)子類對(duì)父類的反向控制距贷。
  • 控制子類擴(kuò)展。模板方法只在特定點(diǎn)調(diào)用鉤子方法吻谋,這樣就只允許在這些點(diǎn)進(jìn)行擴(kuò)展储耐。

6. 優(yōu)點(diǎn)

  • 提高代碼復(fù)用性,去除子類中的重復(fù)代碼滨溉。
  • 提高擴(kuò)展性,不同實(shí)現(xiàn)細(xì)節(jié)放到不同子類中长赞,易于增加新行為晦攒。

7. 缺點(diǎn)

每個(gè)不同的實(shí)現(xiàn)都需要定義一個(gè)子類,這會(huì)導(dǎo)致類的個(gè)數(shù)的增加得哆,設(shè)計(jì)更加抽象脯颜。

8. Android中的源碼分析

Android中View的draw方法就是使用了模板方法模式:

8.1 View的draw方法

public class View{
    //鉤子方法,空實(shí)現(xiàn)
    protected void onDraw(Canvas canvas) {
    }
    //鉤子方法贩据,空實(shí)現(xiàn)
    protected void dispatchDraw(Canvas canvas) {
    }
    //繪制方法栋操,定義繪制流程
    public void draw(Canvas canvas) {
       //其他代碼略

        /*
         *  繪制流程如下:
         *
         *      1. 繪制view背景
         *      2. 如果有需要,就保存圖層
         *      3. 繪制view內(nèi)容
         *      4. 繪制子View
         *      5. 如果有必要饱亮,繪制漸變框和恢復(fù)圖層
         *      6. 繪制裝飾(滑動(dòng)條等)
         */

        if (!dirtyOpaque) {
            drawBackground(canvas);//步驟1. 繪制view背景
        }

        // 如果可能的話跳過第2步和第5步(常見情況)
        final int viewFlags = mViewFlags;
        boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
        boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
        if (!verticalEdges && !horizontalEdges) {
            if (!dirtyOpaque) onDraw(canvas);//步驟3. 繪制view內(nèi)容

            dispatchDraw(canvas);//步驟4. 繪制子View

            // 覆蓋一部分內(nèi)容矾芙,繪制前景
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().dispatchDraw(canvas);
            }

            onDrawForeground(canvas); //步驟6. 繪制裝飾(滑動(dòng)條等)

            return;
        }
}

8.2 說明

  • Viewdraw()方法中定義了一整套的繪制流程苟蹈,這個(gè)流程是固定的寝姿,所有的Android中的View都是按照這個(gè)流程來繪制的逮走。其中drawBackground()這個(gè)方法在View類中是實(shí)現(xiàn)了具體過程的,而onDraw()方法和dispatchDraw()方法在View中都是空實(shí)現(xiàn)殷绍,即都是鉤子方法。不同的子類通過重寫這些空實(shí)現(xiàn)來實(shí)現(xiàn)自身不同的繪制效果谬以。
  • 具體的View门扇,像TextView這些單一的View,就會(huì)重寫onDraw()方法地淀,由于TextView沒有子View失球,所以dispatchDraw()還是空實(shí)現(xiàn);而ViewGroup類含有子View帮毁,需要遍歷子View并繪制实苞,因此需要重寫onDraw()dispatchDraw()
  • 所以作箍,我們自定義View時(shí)必須且只需重寫onDraw()硬梁;自定義ViewGroup時(shí)則需要重寫onDraw()dispatchDraw()

8.3 其他

另外胞得,像Activity的生命周期荧止,AsyncTask等等也是用到了模板方法模式,也興趣的可以研究一下阶剑。

相關(guān)文章閱讀
Android的設(shè)計(jì)模式-設(shè)計(jì)模式的六大原則
一句話總結(jié)23種設(shè)計(jì)模式則
創(chuàng)建型模式:
Android的設(shè)計(jì)模式-單例模式
Android的設(shè)計(jì)模式-建造者模式
Android的設(shè)計(jì)模式-工廠方法模式
Android的設(shè)計(jì)模式-簡單工廠模式
Android的設(shè)計(jì)模式-抽象工廠模式
Android的設(shè)計(jì)模式-原型模式
行為型模式:
Android的設(shè)計(jì)模式-策略模式
Android的設(shè)計(jì)模式-狀態(tài)模式
Android的設(shè)計(jì)模式-責(zé)任鏈模式
Android的設(shè)計(jì)模式-觀察者模式
Android的設(shè)計(jì)模式-模板方法模式
Android的設(shè)計(jì)模式-迭代器模式
Android的設(shè)計(jì)模式-備忘錄模式
Android的設(shè)計(jì)模式-訪問者模式
Android的設(shè)計(jì)模式-中介者模式
Android的設(shè)計(jì)模式-解釋器模式
Android的設(shè)計(jì)模式-命令模式
結(jié)構(gòu)型模式:
Android的設(shè)計(jì)模式-代理模式
Android的設(shè)計(jì)模式-組合模式
Android的設(shè)計(jì)模式-適配器模式
Android的設(shè)計(jì)模式-裝飾者模式
Android的設(shè)計(jì)模式-享元模式
Android的設(shè)計(jì)模式-外觀模式
Android的設(shè)計(jì)模式-橋接模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跃巡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子牧愁,更是在濱河造成了極大的恐慌素邪,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猪半,死亡現(xiàn)場(chǎng)離奇詭異兔朦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)磨确,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門沽甥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乏奥,你說我怎么就攤上這事摆舟。” “怎么了邓了?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵恨诱,是天一觀的道長。 經(jīng)常有香客問我骗炉,道長照宝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任痕鳍,我火速辦了婚禮硫豆,結(jié)果婚禮上龙巨,老公的妹妹穿的比我還像新娘。我一直安慰自己熊响,他們只是感情好旨别,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著汗茄,像睡著了一般秸弛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洪碳,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天递览,我揣著相機(jī)與錄音,去河邊找鬼瞳腌。 笑死绞铃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嫂侍。 我是一名探鬼主播儿捧,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼挑宠!你這毒婦竟也來了菲盾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤各淀,失蹤者是張志新(化名)和其女友劉穎懒鉴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碎浇,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡临谱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奴璃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吴裤。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖溺健,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情钮蛛,我是刑警寧澤鞭缭,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站魏颓,受9級(jí)特大地震影響岭辣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜甸饱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一沦童、第九天 我趴在偏房一處隱蔽的房頂上張望仑濒。 院中可真熱鬧,春花似錦偷遗、人聲如沸墩瞳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喉酌。三九已至,卻和暖如春泵喘,著一層夾襖步出監(jiān)牢的瞬間泪电,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國打工纪铺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留相速,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓鲜锚,卻偏偏與公主長得像突诬,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烹棉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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