開發(fā)中總是說的“鉤子”是什么灾茁?

說起“鉤子(Hook)”這個名詞,可能身為開發(fā)的同學大都聽說過谷炸。所謂Hook機制北专,是從Windows編程中流行開的一種技術(shù)。其主要思想是提前在可能增加功能的地方埋好(預(yù)設(shè))一個鉤子旬陡,這個鉤子并沒有實際的意義拓颓,當我們需要重新修改或者增加這個地方的邏輯的時候,把擴展的類或者方法掛載到這個點即可描孟。這可能不太好理解驶睦,接下來就開始以PHP為例講述下鉤子到底是什么。

講到“鉤子”匿醒,一定要提前說明的是一種設(shè)計模式场航,那就是行為型設(shè)計模式中的模板方法模式,明白了它的話廉羔,會讓我們更容易理解鉤子溉痢。

一.什么是模板方法模式

模板方法模式是一種基于繼承的代碼復(fù)用,它是一種類行為型模式憋他,在其結(jié)構(gòu)中只存在父類與子類之間的繼承關(guān)系孩饼。通過使用模板方法模式,可以將一些復(fù)雜流程的實現(xiàn)步驟封裝在一系列基本方法中竹挡,在抽象父類中提供一個稱之為模板方法的方法來定義這些基本方法的執(zhí)行次序镀娶,而通過其子類來實現(xiàn)某些步驟,從而使得相同的算法框架可以有不同的執(zhí)行結(jié)果揪罕。

簡單而言梯码,這個模式更像是進行婚禮活動(父類)宝泵,按照某一個安排的流程進行,只是每個不同的婚禮(子類)來說忍些,雖然流程是一樣的鲁猩,但是每個流程中,每個婚禮都有自己的玩法罢坝,例如結(jié)婚都要接親廓握,都要被伴娘攔住玩游戲,玩的是什么可能都不一樣嘁酿,然后接回家以后要進行一些禮節(jié)隙券,可能有的遞茶,有的吃餃子什么的各不相同闹司,以代碼的形式說明如下

abstract class AbstractWedding
{
  // 定義婚禮順序
  public function templateMethod()
  {
    $this->appendGame();
    $this->appendMarriage();
  }
  // 婚禮的流程行為需要實現(xiàn)的
  abstract protected function appendGame();
  abstract protected function appendMarriage();
}
// 子類的婚禮進行實現(xiàn)
class Wedding1 extends AbstractWedding
{
  protected function appendGame()
  {
    // 找鞋娱仔,喝酒
  }
  protected function appendMarriage()
  {
    //  教堂宣誓
  }
}
class Wedding2 extends AbstractWedding
{
  protected function appendGame()
  {
    // 發(fā)紅包
  }
  protected function appendMarriage()
  {
    // 親吻新娘
  }
}
// 客戶
class Client
{
  public function __construct()
  {
    $wedding = new Wedding1();
    $wedding->templateMethod();
  }
}

要注意的是,在處理的過程中游桩,要遵循反向控制接口(“好萊塢原則”)牲迫,這個原則是指父類調(diào)用子類的操作,而子類不調(diào)用父類的操作借卧。好萊塢原則于模版方法設(shè)計模式緊密相關(guān)盹憎,因為它在父類中實現(xiàn),除了templateMethod方法外铐刘,父類的其他方法都是抽象和受保護的方法陪每。所以,盡管客戶實例化一個具體類镰吵,但是它調(diào)用了父類中實現(xiàn)的方法檩禾。

二.什么時候使用模板方法

如果已經(jīng)明確算法中的一些步驟,不過這些步驟可以采用多種不同的方法進行實現(xiàn)疤祭,就可以使用模板方法模式盼产。如果算法的步驟不變,可以把這些步驟交給子類去實現(xiàn)勺馆。這種情況下辆飘,可以使用設(shè)計模式來組織抽象類中的基本操作,然后子類去做這些基本操作所需要的具體過程谓传。

還有一種用法可能稍微復(fù)雜一些,可能需要把子類共同的行為放在一個類里面芹关,以避免代碼重復(fù)续挟,畢竟每次實現(xiàn)的子類不回是完全不同的,估計很快就會產(chǎn)生重復(fù)代碼侥衬。

最后一點诗祸,就是可以使用模板方法模式來控制子類拓展跑芳,也就是我們本次需要說的鉤子≈甭可以利用鉤子控制拓展博个,只在鉤子操作所在的某些位置允許拓展。

三.模板方法設(shè)計模式中的鉤子

有的時候功偿,模板方法函數(shù)中可能有一個不想要的步驟盆佣,例如,在我們購買商品的時候要計算最終價格械荷,商品價格+運費+服務(wù)產(chǎn)生費用共耍,不過在有些活動中,顧客商品價格滿100元就可以免運費吨瞎。這里就要使用到模板方法的鉤子痹兜。

也就是說,在模板方法設(shè)計模式中颤诀,利用鉤子可以將一個方法作為模板方法的一部分字旭,不過不一定會用到這個方法。換句話說崖叫,它是方法的一部分遗淳,不過它包含一個鉤子,可以處理例外的情況归露,子類可以為算法增加一個可選元素洲脂,這樣以來,盡管仍然按照父類模板方法建立的順序執(zhí)行剧包,但是有可能并不完全按照模板方法期望的那樣動作恐锦。

不過這可能有點違背之前說的需要遵守的“好萊塢原則”,因為子類沒有遵循父類設(shè)置的順序疆液,好萊塢原則要求只有父類能夠改變框架一铅。鉤子的話更像一個“后門”,進行處理例外的情況堕油。

舉個鉤子的簡單的例子潘飘,就拿免運費的例子進行實現(xiàn)。注意掉缺,雖然子類可以改變鉤子的行為卜录,但是仍然要遵守模板方法中定義的執(zhí)行順序。

// 建立鉤子
abstract class IHook
{
  protected $purchased;
  protected $hookSpecial;
  protected $shippingHook;
  protected $fullCost;
  public function templateMethod($total, $special)
  {
    $this->purchased = $total;
    $this->hookSpecial = $special;
    $this->addTax();
    $this->addShippingHook();
    $this->cost();
  }
  protected function addTax();
  protected function addShippingHook();
  protected function cost();
}

抽象類IHook定義了幾個抽象方法眶明,并且確定了他們的執(zhí)行順序艰毒,這里hook方法放到了中間,實際上它可以放在順序中的任意位置搜囱。$special代表的是是否免運費丑瞧。

// 實現(xiàn)鉤子
class Calc extends IHook
{
  protected function addTax()
  {
    $this->cost = $this->purchased + ($this->purchased * 0.07);
  }
  protected function addShippingHook()
  {
    if(!$this->hookSpecial) { 
      //   這里設(shè)置變量為了更好理解柑土,其實按照題意應(yīng)該是 if($this->cost > 100)
      $this->cost += 5;
    }
  }
  protected function cost()
  {
    return $this->cost;
  }
}

addTax()和cost()都是標準方法,只有一個實現(xiàn)绊汹,不過addShippingHook()的實現(xiàn)有所不同稽屏,其中有一個條件來確定是否要增加運費,這個就是鉤子西乖。 客戶 Client類具體使用不做說明了狐榔。其實就是一個設(shè)置和調(diào)用了。

四.優(yōu)缺點

優(yōu)點
1.提高代碼復(fù)用性 浴栽,將相同部分的代碼放在抽象的父類中
2.提高了拓展性 荒叼,將不同的代碼放入不同的子類中,通過對子類的擴展增加新的行為
3.實現(xiàn)了反向控制典鸡,通過一個父類調(diào)用其子類的操作被廓,通過對子類的擴展增加新的行為,實現(xiàn)了反向控制 & 符合“開閉原則”

缺點
引入了抽象類萝玷,每一個不同的實現(xiàn)都需要一個子類來實現(xiàn)嫁乘,導(dǎo)致類的個數(shù)增加,從而增加了系統(tǒng)實現(xiàn)的復(fù)雜度球碉。

你理解中的“鉤子”是什么樣的呢蜓斧?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市睁冬,隨后出現(xiàn)的幾起案子堕阔,更是在濱河造成了極大的恐慌黍聂,老刑警劉巖宴倍,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宇色,死亡現(xiàn)場離奇詭異,居然都是意外死亡施禾,警方通過查閱死者的電腦和手機脚线,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弥搞,“玉大人邮绿,你說我怎么就攤上這事∨世” “怎么了船逮?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長粤铭。 經(jīng)常有香客問我傻唾,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任冠骄,我火速辦了婚禮,結(jié)果婚禮上加袋,老公的妹妹穿的比我還像新娘凛辣。我一直安慰自己,他們只是感情好职烧,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布扁誓。 她就那樣靜靜地躺著,像睡著了一般蚀之。 火紅的嫁衣襯著肌膚如雪蝗敢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天足删,我揣著相機與錄音寿谴,去河邊找鬼。 笑死失受,一個胖子當著我的面吹牛讶泰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拂到,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼痪署,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了兄旬?” 一聲冷哼從身側(cè)響起狼犯,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎领铐,沒想到半個月后悯森,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡罐孝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年呐馆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莲兢。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡汹来,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出改艇,到底是詐尸還是另有隱情收班,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布谒兄,位于F島的核電站摔桦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜邻耕,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一鸥咖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兄世,春花似錦啼辣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至削解,卻和暖如春富弦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背氛驮。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工腕柜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柳爽。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓媳握,卻偏偏與公主長得像,于是被迫代替她去往敵國和親磷脯。 傳聞我的和親對象是個殘疾皇子蛾找,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353