前言
以小說的筆法寫的設計模式系列文章,你絕對看得懂![首發於公眾號:"聊聊程式碼"]
設計模式系列·王小二需求歷險記(一)
設計模式系列·王小二需求歷險記(二)
設計模式系列·封裝、繼承、多型
設計模式系列·初探設計模式之王小二的疑問
設計模式系列·Facade模式之MVC的煩惱
設計模式系列·Adapter 模式之如何優雅的使用別人的輪子
設計模式系列·類爆炸之Bridge模式
設計模式系列·工廠方法模式之 Code Review
設計模式系列·抽象工廠模式
------華麗的分割線------
流行的MVC架構模式
如今的Web開發,各種框架風起雲湧,勢如破竹。
從國民第一的ThinkPhp到稱霸全球的Laravel,這些框架有一個共同特徵,都採用了MVC的架構模式。
沒有任何意外,王小二的公司用Thinkphp來開發公司的主打產品。
Get新需求
一天,小二剛到公司,正打算坐下來喝杯茶。
老大走了過來:“小二啊,現在有個新的需求。我們們之前提交訂單的模組,需要增加傳送郵件的功能,你看看能不能實現?”
小二想了想說:“沒問題,最多3天搞定!”
看王小二胸有成竹的樣子,老大滿意的點了點頭。
臃腫的Controller
著手開幹吧!小二開啟熟悉的IDE,找到提交訂單模組的Controller。
OMG!不看不知道,一看嚇一跳,這個Controller的程式碼竟然接近2000行。
因為使用者提交訂單時,會與其他模組進行互動,需要的資料也比較複雜。
只見此Controller,從Model層各種拿資料,然後各種邏輯處理,怪不得程式碼到了將近2000行。
“哎,這2000行程式碼,看著就頭疼,可讓我怎麼寫啊”...小二嘆氣道。
“要不再去請教下C哥?”
MVC的煩惱
小二找到C哥,詳細的描述了他的問題。
C哥喝了口水,淡定的說:“這個嘛,我之前也遇到過。”
“您也遇到過,怎麼解決的?”
“這個問題,哈哈,姑且就叫MVC的煩惱吧!MVC將View與Model進行了分離解耦,這固然很好,但很多人就將業務邏輯的處理寫在了Controller裡,導致Controller越來越臃腫,以致最後都無法維護。”
“對對對,您說的太對了,我就經常這樣寫。”
[圖片:臃腫的程式碼]
給Controller減肥
C哥繼續說道:其實,Controller不應該處理過多的業務邏輯。給你舉兩個例子就明白了。
控制器,就像遙控器一樣。
你見過遙控器關心電視怎麼播放視訊嗎?沒有,遙控器只是傳送播放視訊的訊號,具體的播放視訊的細節,遙控器不會關心。控制器,就像將軍一樣。
你見過將軍親自為每位士兵配備武器嗎?細節部分,將軍不必過問,將軍的職責是領兵打仗,這叫各司其職,否則就亂了。
說到這裡,小二恍然大悟:“聽C哥一席話,勝讀十年書啊!”
“既然這樣,就給Controller減減肥吧。”C哥說到
“是啊,但是怎麼減肥呢?”
初識Facade外觀模式
“我給你講一種設計模式-外觀模式,你就懂了”。
“好啊好啊,洗耳恭聽”。
C哥又講到:
外觀模式,提供了統一的介面,用來訪問子系統中的一群介面。外觀模式定義了一個高層介面,使得子系統更加易用。
也就是說,幹一件很複雜的事的時候,你想團隊中每個人都花一年半載去學習如何做這件事嗎?利用外觀模式,我只需要指定一個人去學會這些複雜的步驟,然後我再告訴這個介面人去幹就行了。
Facade外觀模式的應用
“如果讓你實現上面那個需求,你可能會找到使用者提交訂單的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模式真不錯,你看,這樣統一成簡單的介面後:”
1、降低了系統的耦合度。提交訂單的Controller,再也不用與UserController、EmailController等耦合了。現在只需要關心SendEmailFacadeLogic就可以了。
2、並且,使用者使用了Facade模式後,有了統一的入口,就很容易監控客戶對系統的使用了。就如Thinkphp的單一入口一樣。
“嗯嗯。小二真聰明,確實是這樣。”
更多精彩,請關注公眾號“聊聊程式碼”,讓我們一起聊聊“左手程式碼右手詩”的事兒。