以小說的筆法寫的設計模式系列文章,你絕對看得懂![首發於公衆號:"聊聊代碼"]javascript
設計模式系列·王小二需求歷險記(一)
設計模式系列·王小二需求歷險記(二)
設計模式系列·封裝、繼承、多態
設計模式系列·初探設計模式之王小二的疑問
設計模式系列·Facade模式之MVC的煩惱
設計模式系列·Adapter 模式之如何優雅的使用別人的輪子
設計模式系列·類爆炸之Bridge模式
設計模式系列·工廠方法模式之 Code Review
設計模式系列·抽象工廠模式php
------華麗的分割線------java
現在的Web開發,各類框架風起雲涌,勢如破竹。設計模式
從國民第一的ThinkPhp到稱霸全球的Laravel,這些框架有一個共同特徵,都採用了MVC的架構模式。架構
沒有任何意外,王小二的公司用Thinkphp來開發公司的主打產品。mvc
一天,小二剛到公司,正打算坐下來喝杯茶。框架
老大走了過來:「小二啊,如今有個新的需求。我們以前提交訂單的模塊,須要增長髮送郵件的功能,你看看能不能實現?」post
小二想了想說:「沒問題,最多3天搞定!」學習
看王小二成竹在胸的樣子,老大滿意的點了點頭。ui
着手開幹吧!小二打開熟悉的IDE,找到提交訂單模塊的Controller。
OMG!不看不知道,一看嚇一跳,這個Controller的代碼居然接近2000行。
由於用戶提交訂單時,會與其餘模塊進行交互,須要的數據也比較複雜。
只見此Controller,從Model層各類拿數據,而後各類邏輯處理,怪不得代碼到了將近2000行。
「哎,這2000行代碼,看着就頭疼,可以讓我怎麼寫啊」...小二嘆氣道。
「要再也不去請教下C哥?」
小二找到C哥,詳細的描述了他的問題。
C哥喝了口水,淡定的說:「這個嘛,我以前也遇到過。」
「您也遇到過,怎麼解決的?」
「這個問題,哈哈,姑且就叫MVC的煩惱吧!MVC將View與Model進行了分離解耦,這當然很好,但不少人就將業務邏輯的處理寫在了Controller裏,致使Controller愈來愈臃腫,以至最後都沒法維護。」
「對對對,您說的太對了,我就常常這樣寫。」
[圖片:臃腫的代碼]
C哥繼續說道:其實,Controller不該該處理過多的業務邏輯。給你舉兩個例子就明白了。
控制器,就像遙控器同樣。
你見過遙控器關心電視怎麼播放視頻嗎?沒有,遙控器只是發送播放視頻的信號,具體的播放視頻的細節,遙控器不會關心。
控制器,就像將軍同樣。
你見過將軍親自爲每位士兵配備武器嗎?細節部分,將軍沒必要過問,將軍的職責是領兵打仗,這叫各司其職,不然就亂了。
說到這裏,小二恍然大悟:「聽C哥一席話,勝讀十年書啊!」
「既然這樣,就給Controller減減肥吧。」C哥說到
「是啊,可是怎麼減肥呢?」
「我給你講一種設計模式-外觀模式,你就懂了」。
「好啊好啊,洗耳恭聽」。
C哥又講到:
外觀模式,提供了統一的接口,用來訪問子系統中的一羣接口。外觀模式定義了一個高層接口,使得子系統更加易用。
也就是說,幹一件很複雜的事的時候,你想團隊中每一個人都花一年半載去學習如何作這件事嗎?利用外觀模式,我只須要指定一我的去學會這些複雜的步驟,而後我再告訴這個接口人去幹就好了。
「若是讓你實現上面那個需求,你可能會找到用戶提交訂單的Controller,而後在Controller裏寫下面一大堆代碼。是否是?」
/****文件名:SubmitController.class.php(用戶提交模塊controller)****/
//..............接上...2000行代碼..............//
//獲取用戶郵箱
public function get_user_email($uid){
return new User()->get_user_email($uid);
}
//獲取要發送給用戶的內容
public function get_email_content($uid){
return new Email()->get_email_content($uid);
}
//發送郵件
public function send_email($email,$content){
return new Email()->send_email($email,$content);
}
//用戶提交訂單觸發的方法
public function submit(){
$email=$this->get_user_email($uid);
$content=$this->get_email_content($uid);
$this->send_email($email,$content);
}複製代碼
「對對對,我會這麼寫」。
"其實你用的ThinkPhp,有一層叫Logic層,關於業務邏輯處理的部分,你能夠寫在Logic層裏。這樣,Controller層就變得很輕量了,好維護了。"
/****文件名:SendEmailFacadeLogic.class.php(發送郵件Logic)****/
//獲取用戶郵箱
private function get_user_email($uid){
return new User()->get_user_email($uid);
}
//獲取要發送給用戶的內容
private function get_email_content($uid){
return new Email()->get_email_content($uid);
}
//發送郵件
public function send_email($uid){
$email=$this->get_user_email($uid);
$content=$this->get_email_content($uid);
return new Email()->send_email($email,$content);
}複製代碼
/****文件名:SubmitController.class.php(用戶提交模塊controller)****/
//..............接上...2000行代碼..............//
D('SendEmail','Logic')->send_email($uid);複製代碼
「你看,加了Logic層,業務邏輯都放在Logic裏面去處理,Controller是否是瘦了不少呢?Logic層爲Controller提供了一個高層的接口用來發送郵件,也就是Facade模式的應用。」
「小二,明白些了吧?」
「嗯嗯,明白了好多,猶如醍醐灌頂!」
「爲了加深你的理解,我給你畫個簡單的實例圖吧」。
「真的嗎?太謝謝C哥了」。
看了C哥畫的圖,小二小徹小悟了。
「C哥,Facade模式真不錯,你看,這樣統一成簡單的接口後:」
一、下降了系統的耦合度。提交訂單的Controller,不再用與UserController、EmailController等耦合了。如今只須要關心SendEmailFacadeLogic就能夠了。
二、而且,用戶使用了Facade模式後,有了統一的入口,就很容易監控客戶對系統的使用了。就如Thinkphp的單一入口同樣。
「嗯嗯。小二真聰明,確實是這樣。」
更多精彩,請關注公衆號「聊聊代碼」,讓咱們一塊兒聊聊「左手代碼右手詩」的事兒。