淺談設(shè)計模式9——模板模式


昨天那種朝三暮四的性格又來了。看了好幾遍錢能C++的對象生滅,躊躇半天,碼了將近1000來字,最后還是果斷刪掉。畢竟下定決心不要做虎頭蛇尾的事情,況且現(xiàn)在精力確實(shí)有限,如果兩個一塊寫,表面上可以起到互相補(bǔ)充的作用,但是最終肯定是分身,兩樣都做不好。所以,最終還是放棄了新開一個C++版塊的打算。
第二件值得一說的事情是,廁所不僅能解決內(nèi)急,而且也是靈感爆發(fā)的場所。這個遠(yuǎn)在十年前初中的我就已經(jīng)發(fā)現(xiàn),不過畢竟我是個做事虎頭蛇尾的人,所以好習(xí)慣確實(shí)也沒堅持下來。也難怪考研班的政治老師每天晚上一邊上廁所一邊發(fā)微博。
(感覺我這個人不僅朝三暮四,而且忘性極大,剛才計劃說的好幾件事,好像跟沖廁所一樣,瞬間就沒了)那再說說降噪耳機(jī)的事吧。雖然很多人都喜歡熱鬧,但我想還是有一部分人喜歡安靜的——尤其是靜謐詳和的夜。看到一篇文章就說,程序員不要總把錢花在吃上,要多干點(diǎn)別的事。可能這種情況就是針對我來說的。直接切入主題。不知道大家有沒有被身邊那群或者熱血噴張,或者喋喋不休的人打擾,如果是這樣的話,我覺得大家不妨看下“主動降噪耳機(jī)”。不過就是太貴了,拿著微薄補(bǔ)貼的我確實(shí)對奔2000的東西有點(diǎn)望而卻步。好吧。先到此,說多了就是話嘮,總之目前要快快寫完這篇。

模板模式本身并不難,但是,其和策略模式、工廠模式又有相似點(diǎn)。所以可能會有混亂,但是只要牢牢把握住核心,我想三個模式還是很好區(qū)分。由于策略模式位置較靠前,因此,本篇將著重比較策略模式和模板模式兩種模式的異同。順便也算是一種復(fù)習(xí)。

1、背景
模(mu)板模(mo)式其實(shí)說起來很簡單——這些模式我想應(yīng)該都是來源于生活的,活生生的實(shí)例。書上的例子還是挺不錯,所以就借用書上的例子好了。
茶和咖啡我想大家都喝過。沖咖啡的基本步驟:煮開水、沖咖啡、倒杯子里、加奶和糖。沖茶的基本步驟:煮開水、沖茶、倒杯子里、加檸檬(老外的喝法,真想不通加檸檬有啥好喝的,紅茶加蜂蜜倒還不錯)。從上面沖泡茶和沖泡咖啡的步驟來說,有很多相似點(diǎn),而且步驟上都十分類似:
1)煮開水
2)沖飲品
3)倒杯子里
4)加佐料
這樣,就規(guī)范了一套工作流程——框架。利用這個框架,基本的步驟不變——骨架不變,而具體的步驟可以發(fā)生改變——填充物根據(jù)不同子類各具特色。這樣我們就清楚的看到了模板模式的端倪(突然想起昨天看朋友圈出現(xiàn)“涅槃”這個詞——鳳凰的死亡又意味著其重生。也就是同一個個體的生死輪回)。好了,廢話不多說,還是上代碼。

2、模板模式

abstract class Drink
{
    final public void prepare(String order)
    {
        boil();
        steep();
        pour();
        if(askConsumer(order))
            addAccessory();
    }
    
    final public void boil(){}
    final public void pour(){}
    
    abstract public void steep();//沖泡
    abstract public void addAccessory();//加佐料
    
    public boolean askConsumer(String order)//是否加佐料,默認(rèn)加
    {
        return true;
    }
}

class Coffee extends Drink
{

    @Override
    public void steep() {
        System.out.println("coffee");
    }

    @Override
    public void addAccessory() {
        System.out.println("add milk and sugar");
    }
    
    public boolean askConsumer(String order)//重寫方法
    {
        if(order.startsWith("n"))//不加糖和牛奶
            return false;
        return true;
    }
}

class Tea extends Drink
{
    @Override
    public void steep() {
        System.out.println("tea");
    }

    @Override
    public void addAccessory() {
        System.out.println("add honey");
    }
    
    public boolean askConsumer(String age)
    {
        if(age.startsWith("elder"))//老年人喝多了蜂蜜容易得糖尿病
            return false;
        return true;
    }
}

如上程序,共創(chuàng)建了三個類。
1)其中抽象類Drink中的prepare()方法記為模板。其規(guī)定了整個泡茶/沖咖啡的順序。因此,該方法定義為final,從而保證當(dāng)子類繼承的時候,不會覆蓋這個方法。

2)而對于boil()和pour()方法,也是這樣一個道理。因?yàn)椴僮鲗ο蠛筒僮鞣椒ň汛_定下來(煮水:操作對象為水,操作方法為煮)(倒飲料:操作對象為沖調(diào)好的飲料,操作方法為:倒),因此,也被聲明為final方法。

3)注意到兩個abstract方法,這兩個方法即為要根據(jù)其具體情境,需要子類自身實(shí)現(xiàn)的方法。而基類(抽象類)只是調(diào)用這兩個方法,但不實(shí)現(xiàn)這兩個方法。即將方法的實(shí)現(xiàn)延遲的子類中,保證了實(shí)現(xiàn)和接口的解耦。

4)最后一個askConsumer()寫到這里顯然不是可有可無的。這個方法叫做“鉤子(hook)”方法。不過我想,是不是也可以叫“槽(slot)”方法。這個方法要比上面的兩個抽象方法要更進(jìn)一步。基類提供了一個實(shí)現(xiàn)方法,但是子類可以根據(jù)實(shí)際情況,對該方法進(jìn)行覆蓋。確實(shí)還是比較形象的,像鉤子一樣。有鉤子,當(dāng)需要掛香腸(覆蓋實(shí)現(xiàn))的時候,可以掛到上面去,如果沒有鉤子,怎么也無法掛香腸了。

這個鉤子方法在Java中還是比較常見。很多地方都是,基類中提供一個默認(rèn)實(shí)現(xiàn)的接口,如果子類有特殊需要的情況下,可以重新定義這個接口。比如JFrame中的paint方法。以及Applet中的Init()方法等。都是一些鉤子方法。

3、策略模式與模板模式的比較
到這,我想大家應(yīng)該對策略模式已經(jīng)忘得差不多了。反正我已經(jīng)記不住多少了,不過幸好有實(shí)例程序,這個是最好的。

interface FlyBehave
{
      public void fly();
}
class ReallyFly implements  FlyBehave
{
      public void fly(){  println("I can fly");}
}
class CantFly implements FlyBehave
{
      public void fly(){   println("i cant fly") ;}
}
class Duck
{
      Color  color;
      FlyBehave flybehave;//注意此處,采用接口定義屬性,為了實(shí)現(xiàn)多態(tài)
      
      public Duck(FlyBehave f){ flybehave = f;}
      public void fly() {  flybehave.fly();//多態(tài)調(diào)用  }
}

//測試一下
public class Test
{
      Duck  WildDuck=new Duck(new ReallyFly());
      WildDuck.fly();//打印顯示:I can fly
}

從上面的代碼可以看出,策略模式采用組合的方式,將方法封裝到某個類中,再在使用這個方法的類中,聲明其為屬性。這樣通過屬性來調(diào)用方法。

額,其實(shí)說實(shí)話,我不知道作者到底想?yún)^(qū)分啥,看完代碼以后,我覺得策略模式和模板模式完全就是兩碼事。

策略模式是想讓類的調(diào)用的方法更有彈性,也就是說,達(dá)到因地制宜的效果。而模板模式,是為了規(guī)范一套框架,讓所有的子類遵循框架的要求,執(zhí)行相應(yīng)任務(wù)。所以,此處我想還是不要仔細(xì)比較了。相信聰明的你,很快就能領(lǐng)悟這兩種模式到底有什么異同點(diǎn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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