2012-08-06 81 views
9

我正在設計一個帶有CodeIgniter的Web應用程序(但我認爲該問題通常適用於Web應用程序中的MVC模式)。模型類應代表實體還是返回

當我設計了一些數據庫的實體模型類(比如,爲了說明一個BlogEntry),我基本上有兩種選擇:

「典型的面向對象」的方法是,讓類代表的實體,即類的一個實例是一個BlogEntry。在笨,這將導致類似的代碼

class Blogentry extends CI_Model { 
    function load($id) { 
     // Access database 
     $this->id = $dbresult.id; 
     $this->title = $dbresult.title; 
     $this->author = $dbresult.author; 
    } 
} 

要訪問一些博客文章,我會做一個$this->load->model('blogentry');,叫$this->blogentry->load($id),然後用模型類實例的工作。

另一種我經常看到的方法是讓模型返回某個數據結構中的實體。在代碼:

class Blogentry extends CI_Model { 
    function get_entry($id) { 
    // Access database, yielding $dbresult 
    return $dbresult; 
} 

有了這個,我會寫

$this->load->model('blogentry'); 
$the_entry = $this->blogentry->get_entry($id); 
控制器

,並與$the_entry工作。在第二種情況下,該課程更像是factorybuilder課程。

這兩種方法中的任何一種都被認爲是在MVC中做M的「正確方式」?我認爲,我更經常看到第二種方法,但我沒有看到那麼多的MVC-Web應用程序。任何想法爲什麼第一種或第二種方法可能更合適?

+6

看看[這個史詩般的答案](http://stackoverflow.com/a/5864000/871050)作爲參考。 – 2012-08-06 17:29:56

回答

11

首先,CodeIgniter是而不是的一個MVC框架。最適合的範例可能是MVP或類似ORM模板適配器。因此,讓我打破我的答案基於這樣的命名謬誤:

在古典/傳統的MVC(未哪些框架要求是MVC),模型是不是一個類或單個文件,而是包含層所有的域業務邏輯,並且通常僅由諸如Domain Objects,Data Mappers之類的東西構成,以及處理調用實體和域邏輯之間的接口的東西,以便將這樣的代碼保存在控制器之外(例如在MVC中) )。 Tereško names them "services",這對於準官方名稱來說已經足夠了。

因此,在傳統的MVC中,通過「服務」向模型層com請求,這反過來與域對象和數據映射器交互。

很明顯,所有這些與CodeIgniter和其他框架稱爲「MVC」的關係都很小。在這個設計模式中(我簡稱它爲「CIMVC」),Model是一個被Controller調用和操作的類,並且直接與數據庫交互。將數據存儲在模型中的成員變量中並沒有太多的語義意義,但如果您對類似的東西感興趣,可以查看任何用CIMVC編寫的ORM插件/庫。 (儘管ORM解決方案在符合傳統MVC方面不會更好......)

至於常見的做法,我見過的大多數CI應用程序都會將「原始」數據庫數據返回給控制器進行處理;這可以保持模型中的域業務邏輯。我在CIMVC中的個人偏好是最小化/消除模型中的域業務邏輯。

TL;博士 - 「傳統/合適的」 MVC CI中基本上是不可能的,所以試圖迫使你的CI代碼以符合傳統的MVC範式是愚蠢的(並可能會推動你瘋狂)

編輯:爲了澄清一些早期模型層中關於業務邏輯的混淆,是的,您應該在模型層中具有業務邏輯的全部。但是,如果有額外的數據處理(分類,操作等),現在我們進入DRY和SRP違規的危險區域;您希望模型可以重複使用,所以請謹慎添加如此多或特殊的邏輯,以至於在應用程序的其他部分無法使用。

+2

不同意模型中很少到沒有業務邏輯,這正是業務邏輯應該駐留的地方(胖模型/瘦型控制器)。這是因爲biz邏輯可以在需要它的應用程序的任何地方共享。 – 2012-08-06 20:11:32

+0

@MikePurcell你說得對,我顯然沒有對校對的答案進行校對......該模型將處理所有的領域業務邏輯,但是我試圖開車回家的關鍵是關於SOLID編程,特別是SRP 。我會更新答案,以便更清楚。編輯:當我再次閱讀該段時,我不知道*我在想什麼,我在哪裏寫「業務邏輯」......它完全違背了我以前的想法:P – orourkek 2012-08-06 20:44:08

+0

洛爾,沒有概率,認爲有人必須滑倒你的水中有東西。 – 2012-08-06 20:52:34

4

這是一個與MVC範式相關的通用答案,因爲我對CI沒有0經驗,但對Symfony,Zend,Propel和Doctrine有着豐富的經驗。

在使用doctrine時,我發現在特定結構內返回對象數據時,最好添加一個指定所述結構的方法。例如Doctrine_Record對象有一個toArray()方法,它允許我將對象轉換爲數組,或者使用對象訪問器,或者調用toArray()並將該對象作爲數組處理。

// Accessing object data through available methods 
foreach ($object->categories() as $category) { 
    var_dump((string) $category); 
} 

// Accessing object data as an array 
$objectAsArray = $object->toArray(true); 

foreach ($objectAsArray as $element) { 
    var_dump($element['Category']); 
} 

在您如何訪問數據的一天結束時根據自己的喜好,並完全由您決定要如何處理數據,以滿足您的需求。而且在某些情況下,處理數組格式的數據會更快,因爲對象水合往往更受性能影響。

但是,您訪問數據時,建議您將biz邏輯保留在模型層,以便最終不會重複代碼(DRY:不要重複自己)。

+1

據我所知在CodeIgniter模型中沒有類似的方法,但是你可以用db調用返回類型(例如):'$ query-> result()'vs'$ query-> result_array() ' – orourkek 2012-08-06 20:50:32

+0

@orourkek:感謝具體用法,我的答案更通用,因爲我不使用CI。很高興看到他們允許同樣的靈活性。 – 2012-08-06 20:52:00

3

你必須明白的第一件事是CodeIgniter與正確的MVC或MVC設計模式相差甚遠。 CodeIgniter實現的模式沒有正式名稱,但與Ruby on Rails密切相關。

最嚴重的問題來自模型層的實現方式。 Throught出文檔,建議使用active record模式,這本身引入了一些設計問題:

的另一個主要問題是缺乏的意見。視圖應該是包含表示邏輯的實例。這包括選擇哪些模板用於表示從模型層獲取的信息。 視圖不是模板,它們是使用模板的結構。

在CodeIgniter之上創建一個合適的模型層的最好方法是忽略CI_Model,因爲恕我直言,擴展這個類沒有任何好處。相反,創建像Services。這些結構可以充當與模型層交互的接口(不是OO意義上的)。每個服務可以處理多個domain objectsmappers

基本服務從控制器接收命令/消息,它改變模型層的狀態並提供從模型層提取信息的方法。通常提取會發生在視圖實例中,但這在CodeIgniter中是不可能的。信息的提取也會在「控制器」中發生,這些控制器將數據傳遞給模板。

代碼將看起來是這樣的:

class Library 
{ 

    protected $current_document = null; 

    public function acquire_document($id) 
    { 
     $document = load_class('Document', 'domain_object'); 
     $document->set_id($id); 

     $mapper = load_class('Document', 'persistence'); 
     $mapper->fetch($document); 

     $this->current_document = $document; 
    } 

    public function get_document_information() 
    { 
     $document = $this->current_document;   

     if ($document === null) 
     { 
      return 'empty'; 
      // you either did not acquire the document 
      // or document was not found 
     } 
     return $document->get_details(); 
    } 
} 

MVC設計模式實際上是兩層的組合:模型層和表現層(應該主要來自控制器和視圖進行)。

控制器不應該直接在域對象(它們是模型層的一部分)上直接接觸,因爲這意味着你有一個泄漏抽象。

所以,總之,你所說的「模型類」應該返回信息。

+0

您對MVC的描述與Trygve Reenskaug對MVC的描述並不匹配,也不匹配Smalltalk-80 MVC類層次結構,其中有控制器直接與之交互的模型類/對象。 – 2012-08-07 04:10:08

+0

@Lèsemajesté,是的,我遵循Martin Fowler的解釋[[1](http://martinfowler.com/eaaDev/uiArchs.html),[2](http://www.amazon.com/Patterns-Enterprise- Application-Architecture-Martin/dp/0321127420)] MVC設計模式。另外,你必須記住,這是在網絡環境中,任何接近傳統MVC的東西都不可能或幾乎不可能。 – 2012-08-07 04:27:14

相關問題