CodeIgniter 框架擴展:HMVC

CodeIgniter 框架擴展:HMVC

Hierarchical((階層式的))-Model-View-Controller(HMVC)模式,也可以叫做 Layered MVC。

為什麼需要 HMVC

單層 MVC 的限制

原 MVC 架構中只有單層 MVC,單層 MVC 的設計本身沒問題,但隨著系統功能漸變多變複雜時,程式碼卻只能塞進單層 MVC 裡面,程式碼很快就會變得 巨大、縱錯複雜、互相耦合、難以維護。試想一下,一個 Controller 內有 7、8 千行程式碼會容易維護嗎。

原 CodeIgniter MVC 架構(單層 MVC)示意圖:

 application
     |- controllers
         |- controllersA.php
         |- controllersB.php
         |- ...(所有 Controller 都只能放在同一層)
     |- models
         |- models1.php
         |- models2.php
         |- ...(所有 Model 都只能放在同一層)
     |- views
         |- views1
             |- index.php
             |- footer.php
             |- ...
         |- views2
             |- index.php
             |- footer.php

HMVC 帶來的解決方案:

擴展 MVC 架構,讓 MVC 底下可以再擴充一層或多層子 MVC,讓單層 MVC 變成階層式 MVC,而這些擴充出來的 MVC,又稱作為模組、模塊(Modules)。
使用模組好處是:
  • 使每個功能都可以獨立出來
  • 因模組變得獨立,降低各個功能模組之間的耦合性
  • 提高程式碼複用性
  • 每個模組都有自己的 MVC 結構

HMVC 架構示意圖:



CodeIgniter HMVC 擴展模組後,其結構(階層式 MVC)如下:

 application
     |- modules
         |- moduleA 
             |- controllers
                 |- controllers.php
             |- models
                 |- models.php
             |- views
                 |- index.php
                 |- footer.php
                 |- ...
             |- modules (模組 A 底下還可以有子模組...)
                 |- controllers
         |- moduleB 
             |- controllers
                 |- controllers.php
             |- models
                 |- models.php
             |- views
                 |- index.php
                 |- footer.php
                 |- ...
                      |- modules (模組 B 底下還可以有子模組...)
                 |- controllers
         |- ....
     |- controllers
         |- ...
     |- models
         |- ...
     |- views
         |- ...

真實使用情境:

某系統中有個 表單管理 的功能如下圖,但是 表單管理 底下其實有多個功能,這些功能都屬於 表單管理 的範疇:

只有單層 MVC 架構的情況下,這些功能的程式碼都必須寫在同一個 Controller 裡面。因此 單層 Controller 會在很短的時間內便得龐大又複雜
在 HMVC 架構中,則可以把這些功能全部拆分成 表單管理 底下的模組。
這麼做 減輕了單層 Controller 對每個功能模組的耦合。拆出去的模組也變得高內聚,且模組的功能變得更容易複用。

表單管理 HMVC 模組結構


不斷地抽象、封裝

HMVC 可以說是物件導向程式設計的體現。
一個良好的物件導向系統,會隨著程式碼的複雜度上升與變化增加,不斷的進行抽象、封裝。
抽象是將一系列相關的程式碼做歸納,目的是降低人類的認知超載。
而封裝是抽象過程中的一種技術,且物件導向開發傾封裝複雜的過程,以便重複利用。
如果不做抽象會怎樣?嘗試一下下面的範例
// If url is an object, simulate pre-1.5 signature
if (typeof url === "object") {
    options = url;
    url = undefined;
}

// Force options to be an object
options = options || {};

var // Create the final options object
s = jQuery.ajaxSetup({}, options),
// Callbacks context
callbackContext = s.context || s,
var // Create the final options object
s = jQuery.ajaxSetup({}, options),
// Callbacks context
callbackContext = s.context || s,
// Context for global events
// It's the callbackContext if one was provided in the options
// and if it's a DOM node or a jQuery collection
globalEventContext = callbackContext !== s &&
( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
    jQuery(callbackContext) : jQuery.event,
// Deferreds
deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks("once memory"),
// Status-dependent callbacks
statusCode = s.statusCode || {},
// ifModified key
ifModifiedKey,
// Headers (they are sent all at once)
requestHeaders = {},
/**
 *  ajax 全長有 380 行程式碼,故省略。
 **/
上面這段程式碼都是「實作」非同步連線功能的程式碼。
而 jQuery 將這段程式碼抽象成大家熟悉的 $.ajax
如果每次使用非同步連線功能都要寫 380 行程式碼,那真的會瘋掉。

HMVC 除了封裝以外,又讓模組享有 MVC 的功能

HMVC 不只是單純的進行抽象,也讓每個模組享有 MVC 架構的功能

參考資源

留言

這個網誌中的熱門文章

Git Commit Message 這樣寫會更好,替專案引入規範與範例

PHP OO 物件導向基礎教學

Gitlab 合併請求 Merge Request 是什麼?