CodeIgniter 3 框架擴展套件:HMVC

CodeIgniter 3 框架擴展套件:HMVC

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

為什麼需要 HMVC

單層 MVC 的限制

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 架構示意圖:

HMVC 架構示意圖

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 模組結構

不斷地抽象、封裝

HMVC 可以說是物件導向程式設計的體現。

一個良好的物件導向系統,會隨著程式碼的複雜度上升與變化增加,不斷的進行抽象、封裝。

抽象是將一系列相關的程式碼做歸納,目的是降低人類的認知超載。
而封裝是抽象過程中的一種技術,且物件導向開發傾封裝複雜的過程,以便重複利用。

如果不做抽象會怎樣?嘗試一下下面的範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 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 架構的功能

參考資源

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×