一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

常用設(shè)計(jì)模式-模板模式(一)

 景昕的花園 2024-05-13 發(fā)布于北京

前言

我常常覺得人們低估了設(shè)計(jì)模式的作用和意義。它們不僅是簡(jiǎn)歷上的金邊、程序員的黑話,也不僅是常見業(yè)務(wù)的常用處理方式或經(jīng)驗(yàn)總結(jié)。

設(shè)計(jì)模式不僅是這些,它們更是面向?qū)ο笏枷肜碚摻Y(jié)合實(shí)踐的切入點(diǎn)。我們前面聊過抽象、高內(nèi)聚低耦合、封裝繼承多態(tài)、SOLID設(shè)計(jì)原則。它們更偏理論指導(dǎo),離編碼實(shí)踐還有一段距離。而這里要聊的設(shè)計(jì)模式,不僅有扎實(shí)的理論基礎(chǔ),而且實(shí)實(shí)在在地俯下身子、扎根到了實(shí)踐當(dāng)中。

從編碼實(shí)踐的角度來(lái)講設(shè)計(jì)模式,這類文章沒有一萬(wàn)也有八千。細(xì)摳幾種設(shè)計(jì)模式之間的區(qū)別,這類文章寫再多也沒太大意義。這里就不湊這些熱鬧了。

這里,我會(huì)簡(jiǎn)單聊聊幾個(gè)主要設(shè)計(jì)模式的編程應(yīng)用,然后把主要精力放在它們與面向?qū)ο笏枷氲年P(guān)聯(lián)上。另外,在聊過幾種設(shè)計(jì)模式之后,計(jì)劃提供一種復(fù)合模式,作為我使用設(shè)計(jì)模式的“最佳實(shí)踐”,供讀者參考。


模板模式

如果說“用到了接口-實(shí)現(xiàn)類,就用到了策略模式”,那么策略模式可能是我們無(wú)意之間用得最多的設(shè)計(jì)模式。如果排除“無(wú)意中”的使用,只考慮有意識(shí)、有目的情況,我想,模板模式應(yīng)該算得上“使用最多的設(shè)計(jì)模式”,應(yīng)該也是大多數(shù)人第一個(gè)運(yùn)用到實(shí)踐中的設(shè)計(jì)模式。

有意和無(wú)意,有很大差別。

我想,其中的主要原因在于我們大多數(shù)人開發(fā)的都是業(yè)務(wù)系統(tǒng)、業(yè)務(wù)流程。業(yè)務(wù)系統(tǒng)和流程有一個(gè)顯著特點(diǎn):在一套基礎(chǔ)業(yè)務(wù)流程上,改一改這一步、調(diào)一調(diào)那一步,就得到了所謂新業(yè)務(wù)、新流程、新需求。模板模式與這一特點(diǎn)一拍即合,自然就很容易進(jìn)入到開發(fā)實(shí)踐中。


是什么

關(guān)于模板模式的定義,我在網(wǎng)上查到的了很多這樣描述的:

模板模式在一個(gè)抽象類中定義了一個(gè)算法的骨架,而將一些步驟延遲到子類中。

這個(gè)定義里,其它部分都好說,就是“延遲”二字讓人費(fèi)解。延遲一般是指“比xxx更慢/更晚”。在模板模式里,是誰(shuí)比誰(shuí)更慢或更晚呢?

看了一圈,我比較喜歡這個(gè)定義:

The Template Method design pattern is a behavioral design pattern that defines the skeleton of an algorithm in a superclass but allows subclasses to override specific steps of the algorithm without changing its structure.  
模板方法模式是一種行為設(shè)計(jì)模式。它在父類中好定義算法骨架,并允許子類在不修改算法結(jié)構(gòu)的情況下,重寫其中的特定的步驟。

從這個(gè)定義中,我們可以找出模板模式的四個(gè)關(guān)鍵要素:父類、子類、算法骨架、被重寫的步驟,如下圖所示:

父類之于子類有很多種意義。在模板模式中,父類的主要意義在于定義算法骨架。

所謂“算法骨架”,首先是操作流程,其次則是“可重寫的步驟”。有了“可重寫的步驟”,子類才能夠“重寫”這些步驟。但也因?yàn)椴僮髁鞒淘诟割愔卸x好了,因而子類只能重寫個(gè)別步驟的具體實(shí)現(xiàn),而不能修改算法的完整流程、步驟順序等。

網(wǎng)上提到模板模式,大多強(qiáng)調(diào)父類一定是抽象類。其實(shí)未必。盡管不太符合里氏替換原則,模板模式中的父類也可以是普通類。這是后話。

所謂“可重寫步驟”,通常即封裝有部分操作流程的方法。有些時(shí)候,它們也叫“鉤子方法”。子類通過重寫這些方法,來(lái)改寫操作流程中的部分細(xì)節(jié)。這些方法的可見性、入?yún)ⅰ⒎祷刂?,以及“顆粒度”等,都是值得慎重考慮的方面。

在這些方面中,可見性也許是其中最簡(jiǎn)單的一個(gè)。為了兼容跨包的子類,父類的可見性一般都是public。但方法的可見性則不宜過大。有些代碼里一股腦地將它們也定義為public,也有些開發(fā)者把這些方法放到了接口上,實(shí)在沒有必要。

這些方法只服務(wù)于兩個(gè)目標(biāo):組成完整的操作流程,以及供子類重寫。因此,保證這些方法能被子類訪問到即可,其它調(diào)用者一律禁止入內(nèi)。

一個(gè)方法的可擴(kuò)展性,受方法入?yún)⒂绊懞艽?。我見過不少子類A要用參數(shù)ABC、而子類B要用參數(shù)CDE的。如果方法入?yún)⒍x不當(dāng),從子類一擴(kuò)展到子類二時(shí),就免不了一番傷筋動(dòng)骨。


怎么做

明白了模板模式的四個(gè)要素,實(shí)現(xiàn)起來(lái)就很簡(jiǎn)單了:
// 父類,定義算法的骨架public class ParentClass {    // 定義算法的步驟    public final Result templateMethod(Param p) {        Temp1 temp1 = step1(p);        Temp2 temp2 = step2(p, temp1);        Result result = step3(temp1, temp2);        return result;    }
// 定義算法的第一步 protected Temp1 step1(Param p){ // 默認(rèn)實(shí)現(xiàn),略 }
// 定義算法的第二步 protected Temp2 step2(Param p, Temp1 temp1){ // 默認(rèn)實(shí)現(xiàn),略 }
// 定義算法的第三步 protected Result step3(Temp1 temp1,Temp2 temp2){ // 默認(rèn)實(shí)現(xiàn),略 }}
// 具體子類,實(shí)現(xiàn)算法的步驟class ConcreteClassA extends ParentClass { @Override protected Temp1 step1(Param p){ // 修改實(shí)現(xiàn)步驟1,略 }
@Override protected Result step3(Temp1 temp1,Temp2 temp2){ // 修改實(shí)現(xiàn)步驟3,略 }}
// 具體子類,實(shí)現(xiàn)算法的步驟class ConcreteClassB extends ParentClass {
@Override protected Temp2 step2(Param p, Temp1 temp1){ // 修改實(shí)現(xiàn)步驟2,略 }}
// 使用模板模式public class Client { public static void main(String[] args) { ParentClass template = new ConcreteClassA(); template.templateMethod();
template = new ConcreteClassB(); template.templateMethod(); }}

上面的例子看起來(lái)很簡(jiǎn)單,其實(shí)有隱藏的“坑”:“方法步驟”要怎樣拆分比較合適?入?yún)⒑头祷刂狄鯓釉O(shè)計(jì)比較合理?

一般來(lái)說,拆分方法步驟有兩種思路。第一種是在還沒有子類的時(shí)候,就在父類中設(shè)計(jì)好方法步驟,并預(yù)留下供子類重寫的方法。第二種則是沒有子類時(shí),父類不做擴(kuò)展性考慮;在必要時(shí),再根據(jù)子類的擴(kuò)展需求,在父類中拆分方法步驟、設(shè)計(jì)可重寫方法。

這兩種方法,和“自上而下”和“自下而上”的方法論頗有些異曲同工。它們的優(yōu)缺點(diǎn)也可以從類似的角度來(lái)分析。

第一種方法,“自上而下”地設(shè)計(jì)好一個(gè)模板類,為子類預(yù)留下擴(kuò)展空間。如果父類的流程有明確的步驟,或者子類的擴(kuò)展有清晰的方向,那么借助這種自上而下的方法,我們可以設(shè)計(jì)出一套卓有成效的父子類來(lái)。

然而,如果沒有這兩個(gè)前提——“父類的流程有明確的步驟”,或者“子類的擴(kuò)展有清晰的方向”——自上而下的方法就很容易變成過度設(shè)計(jì),最終得到南轅北轍的效果。

第二種方法則是“自下而上”地演化出一套模板和父子類。它很好地彌補(bǔ)了第一種方法的缺陷,但也有明顯的問題。

“按需演化”很容易演變成“按需特化”,得到的模板不倫不類,既復(fù)雜難懂、又難以擴(kuò)展。

自上而下和自下而上,有很大差別。

我個(gè)人更傾向于從上而下的方法論。條件允許時(shí),應(yīng)該優(yōu)先考慮自上而下地設(shè)計(jì),用優(yōu)秀的“頂層設(shè)計(jì)”來(lái)指導(dǎo)、推動(dòng)底層實(shí)現(xiàn)。如果從自下而上入手,也應(yīng)注意審時(shí)度勢(shì),在必要的時(shí)候梳理頂層設(shè)計(jì),優(yōu)化模板類結(jié)構(gòu)。

無(wú)論自上而下還是自下而上,都是一件?費(fèi)時(shí)費(fèi)心的工作。我們?yōu)槭裁匆ㄙM(fèi)時(shí)間精力來(lái)設(shè)計(jì)和使用模板模式呢?模板模式有怎樣的優(yōu)點(diǎn),?又有哪些缺點(diǎn)呢?


?

為什么

模板模式可以提高代碼復(fù)用率和可擴(kuò)展性。這大概?是它最顯而易見的兩個(gè)優(yōu)點(diǎn),這里就不啰嗦了。

?

模板模式還有一個(gè)更高層次的優(yōu)點(diǎn):它是一種入門級(jí)的?建模方式。

模型思維和普通思維,有很大差別。

?

個(gè)人理解,?建模需要抓住事物的核心本質(zhì),并簡(jiǎn)練而明確地描述其組成元素和各元素的組織結(jié)構(gòu)、運(yùn)轉(zhuǎn)規(guī)律。

設(shè)計(jì)模板模式正是這樣一個(gè)過程。我們先要分析業(yè)務(wù)流程,然后把流程按一定順序分解成若干步驟,識(shí)別各步驟的入?yún)⒑头祷刂?,還要把這些步驟區(qū)分為“所有子類通用的”和“允許子類修改的”。完成這些工作之后,我們才能確定父類如何實(shí)現(xiàn)、子類如何重寫。

在這個(gè)過程中,我們得到的步驟、入?yún)⒑头祷刂担鋵?shí)就是這個(gè)流程模型中的“元素”;各步驟的執(zhí)行順序、入?yún)⒑头祷刂档霓D(zhuǎn)換和傳遞,就是這個(gè)模型的運(yùn)轉(zhuǎn)規(guī)律;步驟的分類則可以理解為這個(gè)模型的組織結(jié)構(gòu)的基礎(chǔ):我們需要借助“允許子類修改的步驟”,來(lái)組織父子類結(jié)構(gòu)。

你看,一個(gè)流程模型就這樣拔地而起了。

當(dāng)然,建模沒有這么簡(jiǎn)單, 建好模更不容易。不過,用模型思維來(lái)分析和構(gòu)建系統(tǒng),于系統(tǒng)、于自己都百利一弊——唯一的弊端在于成本偏高。

模板模式作為一種入門級(jí)的建模方式,就像是一扇通往模型思維的大門。當(dāng)我們有意識(shí)、有目的地使用模板模式時(shí),其實(shí)就已經(jīng)站到了這扇門前。推開它、走進(jìn)去,我們會(huì)發(fā)現(xiàn)更廣闊的天地。

推開大門和掉頭走開,有很大差別。


順帶,關(guān)于模型思維的“百利”,這里簡(jiǎn)單列舉幾個(gè)。

模型的7大用途(REDCAPE)

推理:識(shí)別條件并推斷邏輯含義。

解釋:為經(jīng)驗(yàn)現(xiàn)象提供(可檢驗(yàn)的)解釋。

設(shè)計(jì):選擇制度、政策和規(guī)則的特征。

溝通:將知識(shí)與理解聯(lián)系起來(lái)。

行動(dòng):指導(dǎo)政策選擇和戰(zhàn)略行動(dòng)。

預(yù)測(cè):對(duì)未來(lái)和未知現(xiàn)象進(jìn)行數(shù)值和分類預(yù)測(cè)。

探索:分析探索可能性和假說。

《模型思維》

總的來(lái)說,模板模式在需要重用業(yè)務(wù)流程、同時(shí)允許子類重寫某些步驟的場(chǎng)景中非常有用。

然而,在選擇使用模板模式時(shí),我們需要權(quán)衡其帶來(lái)的代碼復(fù)用和行為一致性的優(yōu)點(diǎn),以及可能增加的類數(shù)量和復(fù)雜性的缺點(diǎn),審慎使用。



往期索引

《面向?qū)ο笫鞘裁础?/a>

從具體的語(yǔ)言和實(shí)現(xiàn)中抽離出來(lái),面向?qū)ο笏枷刖烤故鞘裁矗?/section>
公眾號(hào):景昕的花園面向?qū)ο笫鞘裁?/a>

抽象

抽象這個(gè)東西,說起來(lái)很抽象,其實(shí)很簡(jiǎn)單。

花園的景昕,公眾號(hào):景昕的花園抽象

高內(nèi)聚與低耦合

細(xì)說幾種內(nèi)聚

細(xì)說幾種耦合

"高內(nèi)聚"與"低耦合"是軟件設(shè)計(jì)和開發(fā)中經(jīng)常出現(xiàn)的一對(duì)概念。它們既是做好設(shè)計(jì)的途徑,也是評(píng)價(jià)設(shè)計(jì)好壞的標(biāo)準(zhǔn)。

花園的景昕,公眾號(hào):景昕的花園高內(nèi)聚與低耦合

封裝

繼承

多態(tài)》

——“面向?qū)ο蟮娜筇匦允鞘裁???/section>
——“封裝、繼承、多態(tài)?!?/section>

《[5+1]單一職責(zé)原則》
單一職責(zé)原則非常好理解:一個(gè)類應(yīng)當(dāng)只承擔(dān)一種職責(zé)。因?yàn)橹怀袚?dān)一種職責(zé),所以,一個(gè)類應(yīng)該只有一個(gè)發(fā)生變化的原因。
花園的景昕,公眾號(hào):景昕的花園[5+1]單一職責(zé)原則


《[5+1]開閉原則(一)

《[5+1]開閉原則(二)

什么是擴(kuò)展?就Java而言,實(shí)現(xiàn)接口(implements SomeInterface)、繼承父類(extends SuperClass),甚至重載方法(Overload),都可以稱作是“擴(kuò)展”。
什么是修改?在Java中,嚴(yán)格來(lái)說,凡是會(huì)導(dǎo)致一個(gè)類重新編譯、生成不同的class文件的操作,都是對(duì)這個(gè)類做的修改。實(shí)踐中我們會(huì)放寬一點(diǎn),只有改變了業(yè)務(wù)邏輯的修改,才會(huì)歸入開閉原則所說的“修改”之中。
花園的景昕,公眾號(hào):景昕的花園[5+1]開閉原則(一)

《[5+1]里氏替換原則(一)

《[5+1]里氏替換原則(二)

里氏替換原則(Liskov Substitution principle)是一條針對(duì)對(duì)象繼承關(guān)系提出的設(shè)計(jì)原則。它以芭芭拉·利斯科夫(Barbara Liskov)的名字命名。1987年,芭芭拉在一次名為“數(shù)據(jù)的抽象與層次”的演講中首次提出這條原則;1994年,芭芭拉與另一位女性計(jì)算機(jī)科學(xué)家周以真(Jeannette Marie Wing)合作發(fā)表論文,正式提出了這條面向?qū)ο笤O(shè)計(jì)原則

花園的景昕,公眾號(hào):景昕的花園[5+1]里氏替換原則(一)

[5+1]接口隔離原則(一)

[5+1]接口隔離原則(二)

一般我們會(huì)說,接口隔離原則是指:把龐大而臃腫的接口拆分成更小、更具體的接口。
不過,這并不是接口隔離原則的定義。實(shí)際上,接口隔離原則的定義其實(shí)是這樣的……客戶端不應(yīng)被迫依賴它們壓根用不上的接口;或者反過來(lái)說,客戶端應(yīng)該只依賴它們要用的接口。

花園的景昕,公眾號(hào):景昕的花園[5+1]接口隔離原則(一)

[5+1]依賴倒置原則(一)

[5+1]依賴倒置原則(二)

在Java世界里談到依賴倒置原則,相信90%的人都會(huì)立即想起SpringIOC;還有9%的人會(huì)想起“面向接口編程”。最多只有1%的人能想起依賴倒置原則的真正定義。
花園的景昕,公眾號(hào):景昕的花園[5+1]依賴倒置原則(一)

[5+1]迪米特法則(一)
[5+1]迪米特法則(二)

迪米特法則可以用一句話概括:Only talk to your friends。

 “只和你的朋友說話”,這是1987年的表述。2003/2004年左右,Karl Liebertherr對(duì)迪米特法則做了一次升級(jí):由“Only talk to your friends”升級(jí)為了“Only talk to your friends who share your concerns”——“只和與你同憂同樂的朋友說話”。

花園的景昕,公眾號(hào):景昕的花園[5+1]迪米特法則

《常用設(shè)計(jì)模式-策略模式》

策略模式把屬于同一類別的不同行為封裝為某種“策略抽象”,而把這些行為統(tǒng)一為這個(gè)抽象下的某個(gè)“策略實(shí)現(xiàn)”。這樣,我們就可以很靈活地決定在哪種場(chǎng)景下使用哪種“策略”了。

花園的景昕,公眾號(hào):景昕的花園常用設(shè)計(jì)模式-策略模式

《常用設(shè)計(jì)模式-工廠模式(一)》

《常用設(shè)計(jì)模式-工廠模式(二)》

工廠模式的定義其實(shí)很簡(jiǎn)單:提供一個(gè)獨(dú)立組件,用以根據(jù)不同條件選擇并構(gòu)建不同實(shí)例。這個(gè)組件就是“工廠”。

花園的景昕,公眾號(hào):景昕的花園常用設(shè)計(jì)模式——工廠模式(一)


《常用設(shè)計(jì)模式-注冊(cè)器模式(一)》

《常用設(shè)計(jì)模式-注冊(cè)器模式(二)》

注冊(cè)器模式提供了一個(gè)注冊(cè)器,一組相同類型的實(shí)例可以被注冊(cè)到注冊(cè)器上并由后者進(jìn)行保存。調(diào)用方則可以通過注冊(cè)器來(lái)取用這些實(shí)例。
花園的景昕,公眾號(hào):景昕的花園常用設(shè)計(jì)模式-注冊(cè)器模式(一)

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    日本丁香婷婷欧美激情| 成年男女午夜久久久精品| 最近日韩在线免费黄片| 又黄又爽禁片视频在线观看| 91精品视频全国免费| 亚洲天堂国产精品久久精品| 欧美乱码精品一区二区三| 久久精品国产99精品亚洲| 人妻亚洲一区二区三区| 国产在线日韩精品欧美| 色婷婷成人精品综合一区| 亚洲综合精品天堂夜夜| 日韩人妻精品免费一区二区三区 | 国产欧美高清精品一区| 亚洲国产另类久久精品| 亚洲国产综合久久天堂| 日本人妻精品有码字幕| 又色又爽又黄的三级视频| 护士又紧又深又湿又爽的视频| 超碰在线免费公开中国黄片| 污污黄黄的成年亚洲毛片 | 久久人妻人人澡人人妻| 国产一区欧美一区日本道| 大伊香蕉一区二区三区| 国产传媒高清视频在线| 午夜福利视频六七十路熟女| 麻豆精品在线一区二区三区| 黄片在线观看一区二区三区| 国产级别精品一区二区视频| 九九九热视频最新在线| 午夜精品在线观看视频午夜| 免费亚洲黄色在线观看| 懂色一区二区三区四区| 亚洲中文字幕日韩在线| 成年人黄片大全在线观看| 老熟女露脸一二三四区| 国产欧美日韩精品自拍| 国产一级片内射视频免费播放| 国产精品夜色一区二区三区不卡| 一区二区三区亚洲天堂| 久久99亚洲小姐精品综合 |