設計模式系列·Facade模式之MVC的煩惱

前言

以小說的筆法寫的設計模式系列文章,你絕對看得懂![首發於公衆號:"聊聊代碼"]javascript

設計模式系列·王小二需求歷險記(一)
設計模式系列·王小二需求歷險記(二)
設計模式系列·封裝、繼承、多態
設計模式系列·初探設計模式之王小二的疑問
設計模式系列·Facade模式之MVC的煩惱
設計模式系列·Adapter 模式之如何優雅的使用別人的輪子
設計模式系列·類爆炸之Bridge模式
設計模式系列·工廠方法模式之 Code Review
設計模式系列·抽象工廠模式php

------華麗的分割線------java

流行的MVC架構模式

現在的Web開發,各類框架風起雲涌,勢如破竹。設計模式

從國民第一的ThinkPhp到稱霸全球的Laravel,這些框架有一個共同特徵,都採用了MVC的架構模式。架構

沒有任何意外,王小二的公司用Thinkphp來開發公司的主打產品。mvc

Get新需求

一天,小二剛到公司,正打算坐下來喝杯茶。框架

老大走了過來:「小二啊,如今有個新的需求。我們以前提交訂單的模塊,須要增長髮送郵件的功能,你看看能不能實現?」post

小二想了想說:「沒問題,最多3天搞定!」學習

看王小二成竹在胸的樣子,老大滿意的點了點頭。ui

臃腫的Controller

着手開幹吧!小二打開熟悉的IDE,找到提交訂單模塊的Controller。

OMG!不看不知道,一看嚇一跳,這個Controller的代碼居然接近2000行。

由於用戶提交訂單時,會與其餘模塊進行交互,須要的數據也比較複雜。
只見此Controller,從Model層各類拿數據,而後各類邏輯處理,怪不得代碼到了將近2000行。

「哎,這2000行代碼,看着就頭疼,可以讓我怎麼寫啊」...小二嘆氣道。

「要再也不去請教下C哥?」

MVC的煩惱

小二找到C哥,詳細的描述了他的問題。

C哥喝了口水,淡定的說:「這個嘛,我以前也遇到過。」

「您也遇到過,怎麼解決的?」

「這個問題,哈哈,姑且就叫MVC的煩惱吧!MVC將View與Model進行了分離解耦,這當然很好,但不少人就將業務邏輯的處理寫在了Controller裏,致使Controller愈來愈臃腫,以至最後都沒法維護。」

「對對對,您說的太對了,我就常常這樣寫。」

[圖片:臃腫的代碼]

給Controller減肥

C哥繼續說道:其實,Controller不該該處理過多的業務邏輯。給你舉兩個例子就明白了。

  1. 控制器,就像遙控器同樣。
    你見過遙控器關心電視怎麼播放視頻嗎?沒有,遙控器只是發送播放視頻的信號,具體的播放視頻的細節,遙控器不會關心。

  2. 控制器,就像將軍同樣。
    你見過將軍親自爲每位士兵配備武器嗎?細節部分,將軍沒必要過問,將軍的職責是領兵打仗,這叫各司其職,不然就亂了。

說到這裏,小二恍然大悟:「聽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模式真不錯,你看,這樣統一成簡單的接口後:」

一、下降了系統的耦合度。提交訂單的Controller,不再用與UserController、EmailController等耦合了。如今只須要關心SendEmailFacadeLogic就能夠了。
二、而且,用戶使用了Facade模式後,有了統一的入口,就很容易監控客戶對系統的使用了。就如Thinkphp的單一入口同樣。

「嗯嗯。小二真聰明,確實是這樣。」

更多精彩,請關注公衆號「聊聊代碼」,讓咱們一塊兒聊聊「左手代碼右手詩」的事兒。

相關文章
相關標籤/搜索