問題描述
我在理解 MVC 中的視圖概念時似乎有問題,根據(jù)我所讀的內(nèi)容,它們是管理應(yīng)用程序中的表示的層,但我閱讀的許多材料似乎都是與 :驗證、業(yè)務(wù)規(guī)則
也可能在存儲庫、工作單元 和其他.
UI 層主要由視圖和控制器組成.但它們都利用服務(wù)與模型層進行交互.服務(wù)為控制器提供了更改模型層狀態(tài)的方法,并為視圖提供了基于該新狀態(tài)收集信息的方法.
在 Web 上下文中,視圖和控制器形成松散的一對,因為 Web 應(yīng)用程序表現(xiàn)出請求-響應(yīng)性質(zhì).
需要注意的是,雖然控制器可以直接改變當(dāng)前視圖的狀態(tài),但更常見的是這些改變是通過模型來實現(xiàn)的.直接更改視圖的原因之一是,例如,當(dāng)您需要用 JSON 響應(yīng)而不是 XML 時.
盡管也有人認(rèn)為可以為每種輸出格式簡單地實例化不同的視圖并利用多態(tài)性.
什么不是視圖?
有一種普遍的誤解,認(rèn)為視圖只是美化的模板文件.這個錯誤在 RubyOnRails 原型框架發(fā)布后變得非常流行.
視圖不是模板.如果你這樣使用它們,你就破壞了 MVC 和 MVC 啟發(fā)模式背后的核心原則.
如果你假裝模板是視圖,它會對你的架構(gòu)產(chǎn)生巨大的影響.視圖中沒有表示邏輯的位置,因此您可以在控制器或模型層中推送表示邏輯.通常的選擇是控制器",因為大多數(shù)人都明白表示邏輯在模型層沒有位置.
本質(zhì)上,這會導(dǎo)致視圖和控制器的合并.
視圖在做什么?
視圖的職責(zé)是處理表示邏輯.在 Web 上下文中,視圖的目標(biāo)是對用戶產(chǎn)生響應(yīng)(順便說一句,用戶是瀏覽器而不是人).
<塊引用>從技術(shù)上講,可以創(chuàng)建客戶端視圖,即用戶 Web 套接字來觀察模型層,但實際上幾乎不可能實現(xiàn).尤其不是在 PHP 環(huán)境中.
要創(chuàng)建此響應(yīng)視圖,需要從模型層獲取信息,并根據(jù)收集到的數(shù)據(jù),通過將數(shù)據(jù)分發(fā)到模板和呈現(xiàn)來組合響應(yīng),或者有時簡單地發(fā)送 HTTP 位置標(biāo)頭.
<塊引用>使用Post/Redirect/Get時,重定向部分由視圖執(zhí)行,而不是通常人們傾向于做的控制器.
<小時>
高度主觀的部分:
最近我更喜歡使用以下方法與 MVC 交互:
//服務(wù)工廠被注入到構(gòu)造函數(shù)中$controller->{ $method.$command }($request);$response = $view->{ $command }();$response->send();
$method
是當(dāng)前的 REQUEST_METHOD,它已經(jīng)被調(diào)整為一個 REST-like API,而 $command
是人們通常稱為行動".控制器具有用于 GET
和 POST
(另一個)請求的單獨例程.這有助于避免在每個動作"中使用相同的 if
.
在視圖上,我調(diào)用了類似命名的方法,該方法準(zhǔn)備發(fā)送給客戶端的響應(yīng).
<塊引用>警告:我懷疑此設(shè)置包含SRP 違規(guī).把它當(dāng)作你自己的可能是個壞主意.
干式呢?
您可能已經(jīng)注意到,將視圖作為實例存在一個小問題.你最終會得到重復(fù)的代碼片段.例如:菜單或分頁.
讓我們看看分頁..分頁包含邏輯,但此邏輯與模型層無關(guān).該模型沒有頁面"的概念.相反,這一點邏輯將駐留在 UI 層中.但是,如果您的每個視圖都包含或繼承了分頁,那么這顯然違反了 SRP(實際上也違反了其他幾條原則).
為了避免這個問題,你可以(也應(yīng)該,恕我直言)在你的視圖中引入展示對象.
<塊引用>注意:雖然 Fowler 稱它們?yōu)檠菔灸P?,但我認(rèn)為這個名字只會增加整個什么是模型"的混淆.因此,我建議將它們稱為演示對象".
表示對象處理重復(fù)的邏輯片段.這使得視圖更輕",并且在某些方面開始從模型層反映服務(wù)的結(jié)構(gòu).
表示對象和模板之間的交互變得類似于交互域?qū)ο蠛蛿?shù)據(jù)映射器之間.
我總是需要所有這些嗎?
不可以.這種特定方法主要針對代碼,其中 UI 層具有很多復(fù)雜性,您需要將輸入的處理與表示分開,以便保持理智.
如果您的應(yīng)用程序具有非常簡單的 UI,例如 .. emm .. 您正在為更大的集成項目制作 REST API.在這種情況下,實用 選項可以是將每個控制器-視圖對合并為單個類.
在重構(gòu)遺留代碼庫時,這也是一個很好的步驟,因為這種約束較少的方法可以讓您移動整個舊代碼塊.當(dāng)您隔離了這些舊代碼并進行檢查時,一切仍然有效(因為遺留代碼從來沒有任何測試......這就是它成為遺留"的方式),然后您可以開始進一步拆分它,同時專注于分離業(yè)務(wù)邏輯來自用戶界面.
<小時><塊引用>P.S. 我自己仍在努力尋找一種最好的處理視圖的方法.這篇文章不是一個答案,更像是我目前理解的快照.
I have to seem problems grasping the concept of Views in MVC, they are, according to what I've read, the layer that manages the presentation in the aplication, but many of the material I've been reading seem to be different regarding this matter in this one from PHP Master.com.
The View is a class with functions that return some HTML code, where is the rest of my HTML? should it be put in independent .html pages that access this View code?
In this article, from php-html.net the View is a simple HTML file with a .php extension, but how are they accessing that data? I see no require()
or anything like the instantiations in the first tutorial.
Note: the MVC and MVC-inspired patterns are advanced constructs. They are meant to be used in codebases where ordinary object-oriented (that follows SOLID and other guidelines) code starts to become unmanageable. By introducing this pattern you would impose additional constraints, which then lets you to contain very complex applications. MVC is not meant for "hello world" apps.
Let's start from the beginning ...
The core idea behind MVC and MVC-inspired design patterns is Separation of Concerns. Said separation is two-fold:
- model layer is separate from UI layer:
- views are separated from controllers
Model layer (not "class" or "object") would contain several groups of structures, each dealing with as different aspect of business logic. The major parts would be:
- domain objects: validation, business rules
- storage abstraction: persistence and caching of data from domain objects
- services: application logic
Also there might be mixed in repositories, units of work and others.
UI layer mostly consists of views and controllers. But they both utilize services to interact with the model layer. Services provide the way for controllers to change the state of model layer and for the views to gather information based on that new state.
In context of web the views and controllers form a loose pair, because of the request-response nature that web applications exhibit.
It should be noted that although controllers can alter the state of the current view directly, it's more common that these changes are effected through the model. One reason to alter the view directly is, for example, when instead of XML you need to respond with JSON.
Though it also could be argued that one could simple instantiate a different view for each output format and take advantage of polymorphism.
What is not view?
There is a widespread misconception that views are simply glorified template file. This mistake became extremely popular after release of RubyOnRails prototyping framework.
Views are not templates. If you use them as such, you break the core principle behind MVC and MVC-inspired patterns.
If you pretend that templates are views, it has an enormous impact on your architecture. There is no place for presentation logic in the view, therefore you push the presentation logic either in controller or model layer. The usual choice is "controller", because most of people understand that presentation logic has no place in model layer.
Essentially, this causes a merger of views and controllers.
What is view doing?
The responsibility of the view is to deal with presentation logic. In context of web the goal for view is to produce a response to the user (which, btw, is the browser not the human).
Technically it would be possible to create client side views, that user web sockets to observe model layer, but in practice it's virtually impossible to implement. Especially not in PHP environment.
To create this response view acquires information from model layer and, based on gathered data, either assembles response by distributing data to templates and rendering or sometimes simple sending a HTTP location header.
When using Post/Redirect/Get, the redirect part is performed by the view, not the controller as often people tend to do.
Highly subjective bit:
Lately I have preferred to interact with MVC using following approach:
// the factory for services was injected in constructors
$controller->{ $method.$command }($request);
$response = $view->{ $command }();
$response->send();
The $method
is the current REQUEST_METHOD, that has been adjusted fake a REST-like API, and the $command
is what people usually call "action". The controller has separate routines for GET
and POST
(an other) requests. This helps to avoid having same if
in every "action".
And on the view I call similarly named method, that prepares a response that is sent to the client.
Warning:I suspect that this setup contains an SRP violation. Adopting it as your own might be a bad idea.
What about DRY?
As you might have noticed already, there is a slight problem with having views as instances. You would end up with repeating pieces of code. For example: menu or pagination.
Lets look at pagination .. The pagination contains logic, but this logic is not related to the model layer. The model has no concept of "page". Instead this bit of logic would reside in the UI layer. But if each of your views contains or inherits pagination, then it would be a clear violation of SRP (and actually several other principles too).
To avoid this issue you can (and should, IMHO) introduce presentation objects in your views.
Note: while Fowler calls them "presentation models", I think that name just adds to the whole 'what is model' confusion. Therefore I would recommend to call them "presentation objects" instead.
The presentation objects deal with repeated pieces of logic. This makes the views much "lighter", and in some aspects starts to mirror the structure of services from the model layer.
The interaction between presentation objects and templates becomes similar to the interaction between domain objects and data mappers.
Do I always need all of this?
No. This specific approach is heavily geared towards code, where the UI layer has a lot of complexity and you need to separate the handling of input from presentation just to sane sane.
If your application has very simple UI, like .. emm .. you are making REST API for a larger integrated project. In such the pragmatic option can be to just merge every controller-view pair into single class.
It also can be a good step, when refactoring a legacy codebase, because this less-constrained approach lets you move entire chunks of old code. When you have isolated such pieces of older code and checked, that everything still works (since legacy code never has any tests .. that's how it becomes "legacy"), you then can start splitting it up further, while focusing on separating business logic from UI.
P.S. I myself am still struggling with figuring out a way how best to deal with views. This post is less of an answer and more like a snapshot of my current understanding.
這篇關(guān)于理解 PHP 中的 MVC 視圖的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!