2013-02-04 43 views
1

好吧,我現在基本的MVC概念,我知道有類似的問題,但仍然沒有找到明確的答案。閱讀關於MVC我發現了一些矛盾的例子,所以我想找出哪個更好。MVC概念 - 誰的責任是加載模型?

我應該使用我的控制器從模型加載數據並將該數據傳遞給視圖,還是讓視圖從模型加載數據並使用控制器來選擇適當的視圖。

更自然(右)的方式對我來說是控制器應加載模型,但比一次,如果我有需要有2點不同的看法,例如相同的內容:

  1. 視圖顯示簡單的文章文本
  2. 視圖顯示相同的文章文本,但也顯示文章作者信息框。

讓我困惑的是我有一個單獨的請求,顯示我的文章與ID 33.在第一種情況下一切都清楚,但現在我的第二個視圖呈現使用不同的模板,顯示額外的數據(關於作者) ,那麼我應該讓視圖從模型(關於作者)請求數據,還是應該由控制器完成整個邏輯?

這很混亂,因爲現在控制器應該根據視圖應該呈現的模板從模型中請求適當的數據。

希望我意義:)

回答

1

簡短回答:將模型傳遞給控制器​​和視圖。

長答案:在MVC中,控制器不會「從模型加載數據,然後將該數據傳遞給視圖」。該視圖與模型有直接關係,並從中請求數據。請參閱:How is MVC supposed to work in CodeIgniterhttp://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller:「視圖請求來自模型的信息,它需要生成輸出表示。」因此,爲了實現鬆耦合,可以完全獨立地啓動模型視圖和控制器,並將它們傳遞給對方。

這允許嚴格分離關注MVC的擁護者,並允許您重用任何其他組件,因爲沒有任何硬編碼。

喜歡的東西:

$model = new Model; 
$controller = new Controller($model); 
$view = new View($model, $controller); 
echo $view->output(); 

控制器不應該選擇視圖,也不應該選擇模型。通過將這個責任放在控制器中,控制器不能與其他視圖或模型重複使用。

編輯:我更新了這個回答tresko關於爲什麼視圖需要知道其控制器的評論。

該視圖需要控制器以避免將控制器硬編碼到視圖中。這是爲了讓視圖知道它在當前上下文中與哪個控制器配對並可以回發給它。

事件(用戶操作)在視圖中觸發,需要由控制器處理。

有3種方式這樣做的:

1)硬編碼視圖:控制器的關係,這是通過使用<a href="/some/hardcoded/route"實現在網絡上;或<a href="' . $this->router->create('someController, 'action') . '>'這消除了與其他任何不希望的控制器一起使用視圖的可能性。

2)將控制器傳遞給視圖,讓視圖知道它的事件將被觸發到哪個控制器。在網絡上,使用這種方法,該視圖還需要一個將控制器動作轉換爲路由的路由器。例如<a href="' . $this->router->getRoute($this->controller, 'action') . '>'

3)通視圖控制器和對視圖控制器設置操作:(控制器代碼)$this->view->setEvent('buttonClick', $this->router->getRoute($this, 'action')) ...(查看代碼)<a href="' . $this->getEvent('buttonClick') . '>'

其中,

1)是因爲它嚴重影響靈活性,所以最不可取。該視圖只能在非常特定的控制器上調用操作。

2)開發人員的工作量最少,但每個控制器都需要一個特定的接口。

3)這提供了最大的技術靈活性,但開發人員需要做更多的工作,並且控制器需要了解很多關於其視圖的內容,除了API之外,它必須知道視圖中可用的事件。如果視圖更新並且有新的操作,每個控制器都需要更新以解釋它。這同樣適用於2),但是因爲2可以使用接口輕鬆處理,所以追蹤使用它的每個類都容易得多。

在我看來,2和3都是很好的方法,但2更好,因爲它允許一個更強大的系統,並允許最重用,缺點是控制器必須實現特定的接口。 3允許控制器具有任何接口,但它必須對其視圖有相當多的瞭解。

CakePHP和其他流行的框架傾向於硬編碼關係(例如http://book.cakephp.org/2.0/en/views.html)在這裏的例子中,echo $this->Html->link('edit', array('action' => 'edit', $post['Post']['id'])); ?>鏈接只能進入「編輯」控制器。這嚴重影響重用。

+0

謝謝。但是這樣看,我問自己誰需要控制器?我的意思是在應用程序啓動後,我通常可以根據請求參數調用適當的視圖,這將加載視圖,視圖會從模型中請求數據並輸出它:) – kruno

+0

視圖爲什麼控制控制器?如果控制器不可重用,爲什麼你將它注入一個你期望可重用的類中?視角是否期待一個嚴格定義足跡的控制器?在MVC的定義中,哪裏表示View在Controller上執行命令? –

+1

http://upload.wikimedia.org/wikipedia/commons/f/fd/MVC-Process.png下面是維基百科的「MVC過程」圖形。它顯示用戶「使用」控制器。然而,「控制器」對用戶來說沒有意義,他們「使用」視圖。從Java藍圖模型視圖控制器:http://briggs.myweb.port.ac.uk/WEBP/notes/images/mvc-structure-generic.gif「查看 - 發送用戶手勢到控制器」。控制器從視圖中被調用,這是用戶唯一真正與之交互的東西。 –

-1

我的建議是,對數據源可以欣賞相結合的邏輯應該在控制器完全發生。視圖不應該綁定到特定的數據源。例如,如果您有一個使用帶命名佔位符的Smarty語法(或類似語法)的視圖,則可以使用任何數據源,文本,模型等來提供要呈現到模板中的信息。如果視圖與模型相關聯,則需要修改模型和視圖,並且意識到對其他模型的影響。

這樣的緊密耦合會導致更多的問題,因爲意外地忽略了比鬆散耦合更多的問題,從而減少意外摔壞機會的機率。

例:

class Page_Controller extends Controller { 

    // __construct/__destruct/__callStatic/__call/etc, whatever you need in your implementation 

    // ------------------------------------------------------- 
    // Adjust to suit your situation for passing data 
    // This controller doesn't care where objSource comes from 
    // ------------------------------------------------------- 
    private function pageSpecificImplementation($objSource = null){ 

    // using a factory class - but assume a view is created in whatever way works for you 
    // the key thing here is that the view could be anything that can be returned as a string - but use whatever works for you 
    $tplMain = make::view('template-url-or-path')->assign(array(
     'placeholder1' => $objSource->value1, 
     'placeholder2' => $objSource->value2 
    )); 

    $tplSub = make::view('template-url-or-path')->assign($objSource); 

    $tplMain->assign('sub',$tplSub->render())->render(); 

    // $tpl is some form of html? csv?, who knows - not relevant at THIS stage 

    // okay - now I know what I want to do! 
    // decide what to do with it here - output headers for html 
    // save to a file 
    // output and cache the output, whatever works for you here 
    // output to pdf? 
    // send as an email? 
    output::html($tplMain, $cacheable, $cachetime...); 
    // output::email($tplMain, $extra_params); 
    // output::pdf($tplMain, $extra_params); 
    } 

} 

在這裏,您使用的視圖,沒有它緊密耦合到輸出。您的控制器可以根據運行時正在播放的任何業務規則來修改輸出,但是數據源不受限於視圖,輸出也不與視圖綁定。

我建議'一些'實施,按照類似的原則分離。 YMMV取決於你在做什麼以及你想如何實現它,但是嘗試在MVC中保持每個元素分離。

在某些實現中,您將看到在視圖中「替換」事物的邏輯,而不提及「什麼」視圖。這通常在Smarty中完成。該視圖可以由控制器的流程確定。可以從多個模型或其他來源獲取數據,這些數據可能會或可能不會影響哪個視圖是合適的。

所以,你應該明確地從視圖中分離加載數據。將它保存在控制器中,這是決策的地方。視圖不應該與模型連接,除非你有一個特定的使用案例,比如帶有緊密耦合主題視圖的主題模型,其中沒有涉及額外的業務邏輯(不太可能,但可能?)。

+0

倒票應該附帶說明,以便海報可以刪除或修改爲更有用,而不是讓他們在這裏無法爲其他人改進。 – MyStream

+0

我沒有投票,但這顯然是因爲你實現了接近'MVP'的東西,並打破了'SRP' – Yang

+0

@DaveJust - 你打破SRP規則是什麼意思? – MyStream