Trong MVC, có thể / nên lấy dữ liệu cơ bản từ Mô hình trong Chế độ xem không?


10

Với khái niệm 'bộ điều khiển mỏng, mô hình béo' và sự chấp nhận chung rằng Chế độ xem có thể gọi trực tiếp trên Mô hình khi yêu cầu dữ liệu cho đầu ra, bạn có nên xem xét xử lý các phần 'nhận và hiển thị' các yêu cầu trong Chế độ xem chứ không phải Bộ điều khiển? Ví dụ: (cố gắng giữ mã khá chung chung):

Bộ điều khiển

<?php

class Invoice extends Base_Controller {

    /**
     * Get all the invoices for this month
     */

    public function current_month() {

        // as there's no user input let's keep the controller very skinny,
        // DON'T get data from the Model here, just load the view

        $this->load->view('invoice/current_month');

    }

}

Lượt xem

<?php

// directly retrieve current month invoices here

$invoices = $this->invoice_model->get_current_month();

// get some other display-only data, e.g. a list of users for a separate list somewhere on the page

$users = $this->user_model->get_users();

?>

<h1>This month's invoices</h1>

<ul>
<?php foreach ($invoices as $invoice) { ?>

<li><?php echo $invoice['ref']; ?></li>

<?php } ?>
</ul>

Đối với tôi, điều này ít nhất có ý nghĩa trong trường hợp yêu cầu về cơ bản chỉ là Chế độ xem. Tại sao Bộ điều khiển phải thu thập và chuyển dữ liệu đến Chế độ xem khi nó có thể tự truy xuất dữ liệu? Điều này để Bộ điều khiển mở hoàn toàn để xử lý 'Cấp ứng dụng' (ví dụ: xử lý các yêu cầu GET / POST, quản lý quyền truy cập và quyền, v.v.) cũng như giữ cho các Mô hình có thể sử dụng lại và tất cả các nội dung tốt khác.

Nếu ví dụ này được mở rộng để cho phép người dùng lọc kết quả, Bộ điều khiển sẽ chỉ xử lý POST từ biểu mẫu và chuyển các bộ lọc sang Chế độ xem, sau đó sẽ yêu cầu lại dữ liệu, lần này với các bộ lọc.

Đây có phải là một cách tiếp cận hợp lệ để phát triển một ứng dụng MVC? Hay tôi đang xem một phần quan trọng của vai trò mà Người điều khiển nên đóng?

Câu trả lời:


17

Vâng, về mặt kỹ thuật có thể được thực hiện. Không, nó không nên được thực hiện. Và vâng, bạn đang thiếu một chút những gì bộ điều khiển dành cho.

Bộ điều khiển ở đó để tách rời Chế độ xem khỏi Mô hình. Việc tách rời có lợi vì bạn nên xem Chế độ xem gần như là mã bỏ đi. Khi công nghệ UI của bạn thay đổi, bạn muốn giảm thiểu việc làm lại cần thiết trong việc tạo Chế độ xem mới. Bộ điều khiển cho phép tách rời và cung cấp một vị trí cho mã của bạn sẽ tồn tại thông qua các công nghệ UI.

Nó cũng hoạt động ngược lại nếu bạn cần thêm hoặc thay đổi Mô hình của mình. Tất cả các thay đổi ngược dòng sẽ được chứa trong Bộ điều khiển và Chế độ xem của bạn sẽ được để lại một mình.

Các rủi ro khác là trong khi các View là rất đơn giản hiện nay , bạn chỉ còn lại ít đảm bảo rằng nó sẽ vẫn còn đơn giản như vậy trong suốt cuộc đời của nó. Bằng cách gọi Mô hình trực tiếp từ Chế độ xem (rất đơn giản), bạn đã mở cửa một chút để cho phép thực hành xấu thêm vào sau này khi Chế độ xem rất đơn giản cần trở nên không đơn giản. Một nhà phát triển trong tương lai sẽ được khuyến khích thực hiện nhiều cuộc gọi Mô hình hơn từ Chế độ xem không đơn giản thay vì cấu trúc lại mã và tương tác với Bộ điều khiển.


1
Câu trả lời tuyệt vời, cảm ơn bạn. Mở rộng kịch bản 'nhìn về phía trước' của bạn một chút; nếu có thông tin chung trên một trang riêng biệt với những gì được yêu cầu (ví dụ: người dùng đang xem một sản phẩm cụ thể, một danh sách chung về 'ưu đãi đặc biệt mới nhất' được hiển thị ở bên cạnh) làm thế nào / nên thực hiện cuộc gọi đến offers_model->get_latest()đâu? Thêm phương thức này vào mọi phương thức trong bộ điều khiển (như tôi đã cố gắng một cách dại dột trước đây) có vẻ như quá mức cần thiết và rõ ràng là không KHÔ.
Adam Westbrook

2
@AdamWestbrook Hãy xem MVVM. Phần ViewModel có thể giải quyết vấn đề cụ thể này. Bạn có thể thêm offers_model->get_latest()vào một ProductViewModellớp cơ sở hoặc một cái gì đó tương tự.
Zachary Yates

1
Tuyệt vời, tôi chắc chắn sẽ xem xét MVVM, cảm ơn một lần nữa.
Adam Westbrook

Câu trả lời rất tốt, sẽ thách thức giữ ngôi sao này. Cá nhân tôi cũng là một fan hâm mộ lớn của MVVM :)
Benjamin Gruenbaum

@BenjaminGruenbaum Bạn có đang sử dụng MVVM trong PHP không? Nếu vậy bạn có đang sử dụng một khung cụ thể cho nó không?
Adam Westbrook

6

Đưa ra khái niệm 'bộ điều khiển mỏng, mô hình béo' và sự chấp nhận chung rằng Chế độ xem có thể gọi trực tiếp trên Mô hình khi yêu cầu dữ liệu cho đầu ra

Không. Điều này không đúng. Xem không thể gọi trực tiếp trên Mô hình. Các khung nhìn không được có quyền truy cập vào các đối tượng Model, trừ khi vì một lý do nào đó, lập trình viên đã đưa các đối tượng đó ra View.

Người ta có nên xem xét xử lý các phần 'nhận và hiển thị' các yêu cầu trong Chế độ xem chứ không phải Bộ điều khiển không?

Điều đó về cơ bản xóa Bộ điều khiển và đánh bại điểm có chúng.

Tại sao Bộ điều khiển phải thu thập và chuyển dữ liệu đến Chế độ xem khi nó có thể tự truy xuất dữ liệu?

Bộ điều khiển không thu thập dữ liệu. Mô hình thực hiện việc thu thập dữ liệu. Bộ điều khiển quyết định nếu dữ liệu này sẽ được chuyển đến dạng xem. View chỉ thực hiện việc trình bày dữ liệu.

Nếu ví dụ này được mở rộng để cho phép người dùng lọc kết quả, Bộ điều khiển sẽ chỉ xử lý POST từ biểu mẫu và chuyển các bộ lọc sang Chế độ xem, sau đó sẽ yêu cầu lại dữ liệu, lần này với các bộ lọc.

Không.

Bộ điều khiển kiểm tra xem dữ liệu đã đăng có hợp lệ hay không, sau đó nó chuyển dữ liệu này dưới dạng tùy chọn cho Mô hình, sau đó sẽ truy vấn nguồn dữ liệu và trả lại dữ liệu và Bộ điều khiển chuyển dữ liệu đó đến Chế độ xem.

Đây có phải là một cách tiếp cận hợp lệ để phát triển một ứng dụng MVC? Hay tôi đang xem một phần quan trọng của vai trò mà Người điều khiển nên đóng?

Bộ điều khiển hoạt động như một trình xử lý các yêu cầu của trình duyệt. Một người điều phối gửi yêu cầu đến hành động của bộ điều khiển, đến lượt nó, lan truyền yêu cầu ra cho các Mô hình. Các mô hình chứa tất cả logic nghiệp vụ (đây là phần chất béo) và trả lại dữ liệu cho bộ điều khiển. Sau đó, bộ điều khiển có thể đơn giản hóa và điều chỉnh dữ liệu để Chế độ hiển thị dễ dàng hơn.

Quan điểm của Chế độ xem là tách rời cấu trúc và sự phụ thuộc giữa cách trình bày HTML và DataSource. Trong khi điều này có thể khó khăn. Lượt xem không phải lúc nào cũng hiển thị dữ liệu đến trực tiếp từ Mô hình. Bộ điều khiển thường thêm dữ liệu bổ sung có liên quan.

Tôi chắc chắn có rất nhiều hướng dẫn trên MVC. Tôi khuyên bạn nên đọc một số trong số họ.


Cảm ơn Mathew. Để làm rõ, cho đến bây giờ tôi luôn tách riêng Chế độ xem và Mô hình với Bộ điều khiển như đã đọc và đề xuất. Tuy nhiên, kể từ khi bắt đầu đọc về việc giữ các bộ điều khiển 'gầy', tôi đã tự hỏi những gì nên / có thể được chuyển ra khỏi chúng, có vẻ như quá trình suy nghĩ dẫn tôi đến câu hỏi này là một hoặc hai bước quá xa!
Adam Westbrook

Khi bạn bắt đầu nhận Mô hình được sử dụng bởi nhiều bộ điều khiển. Nhu cầu béo của họ trở nên rất rõ ràng. Khi Chế độ xem bắt đầu chứa nhiều PHP thì bạn biết bộ điều khiển của mình sẽ mỏng. Khi bộ điều khiển của bạn rất béo. Thật khó để khiến các bộ điều khiển khác hoạt động theo cùng một cách (ví dụ: thêm dịch vụ API).
Phản ứng

3

Tôi thấy câu hỏi của bạn rất thú vị vì tôi gặp phải vấn đề tương tự khi học Python gần đây.

Trong khi các câu trả lời đưa ra một lập luận thuyết phục, tôi nghĩ rằng tôi sẽ thêm một ý kiến ​​khác mà tôi đã gặp trong đó Chế độ xem có trạng thái của Mô hình mà không thông qua Trình điều khiển.

MVC

Điều quan trọng cần lưu ý là cả khung nhìn và bộ điều khiển đều phụ thuộc vào mô hình. Tuy nhiên, mô hình phụ thuộc vào chế độ xem cũng như bộ điều khiển. Đây là một trong những lợi ích chính của sự tách biệt. Sự tách biệt này cho phép mô hình được xây dựng và thử nghiệm độc lập với trình bày trực quan. Sự tách biệt giữa khung nhìn và bộ điều khiển là thứ yếu trong nhiều ứng dụng máy khách phong phú và trên thực tế, nhiều khung giao diện người dùng thực hiện các vai trò như một đối tượng. Mặt khác, trong các ứng dụng Web, sự tách biệt giữa chế độ xem (trình duyệt) và bộ điều khiển (các thành phần phía máy chủ xử lý yêu cầu HTTP) được xác định rất rõ.

Model-View-Controller là một mẫu thiết kế cơ bản để tách logic giao diện người dùng khỏi logic nghiệp vụ. Thật không may, sự phổ biến của mô hình đã dẫn đến một số mô tả bị lỗi. Cụ thể, thuật ngữ "bộ điều khiển" đã được sử dụng để chỉ những thứ khác nhau trong các bối cảnh khác nhau. May mắn thay, sự ra đời của các ứng dụng Web đã giúp giải quyết một số sự mơ hồ vì sự tách biệt giữa khung nhìn và bộ điều khiển quá rõ ràng.

Trong lập trình ứng dụng trong Smalltalk-80: Cách sử dụng Model-View-Controller (MVC) [Burbeck92], Steve Burbeck mô tả hai biến thể của MVC: mô hình thụ động và mô hình hoạt động.

Mô hình thụ động được sử dụng khi một bộ điều khiển thao tác riêng mô hình. Bộ điều khiển sửa đổi mô hình và sau đó thông báo cho khung nhìn rằng mô hình đã thay đổi và cần được làm mới (xem Hình 2). Mô hình trong kịch bản này hoàn toàn độc lập với khung nhìn và bộ điều khiển, điều đó có nghĩa là không có phương tiện để mô hình báo cáo các thay đổi trong trạng thái của nó. Giao thức HTTP là một ví dụ về điều này. Không có cách đơn giản nào trong trình duyệt để nhận các bản cập nhật không đồng bộ từ máy chủ. Trình duyệt hiển thị chế độ xem và phản hồi đầu vào của người dùng, nhưng nó không phát hiện ra những thay đổi trong dữ liệu trên máy chủ. Chỉ khi người dùng yêu cầu làm mới một cách rõ ràng thì máy chủ mới được thẩm vấn để thay đổi.

MVC - Mô hình thụ động

Tôi không ở vị trí để nói ý kiến ​​nào là "đúng", và thành thật mà nói, tôi hơi bối rối hơn sau khi đọc câu trả lời ở đây và bài viết được liên kết.

Toàn văn bài viết tại đây .


Phải, và một thứ khác làm tăng thêm sự nhầm lẫn là máy khách-máy chủ, mà SmallTalk MVC ban đầu không thực sự chiếm được. Trong máy khách-máy chủ (ví dụ với javascript), có các mô hình, khung nhìn và bộ điều khiển hướng trình bày trên máy khách, và các khung nhìn và bộ điều khiển hướng miền trên máy chủ, mặc dù máy chủ cũng thực hiện một số nhầm lẫn xử lý theo hướng trình bày. Ngoài ra, đôi khi chúng tôi muốn một chế độ xem tên miền có một số sự kiên trì, có nghĩa là các tham số chế độ xem tạo thành mô hình của riêng chúng, đó không nhất thiết là một phần của mô hình miền.
Erik Eidt

Cảm ơn bạn đã liên kết, tôi biết tôi đã không điên khi nghĩ về điều này! Đây thực chất là những gì tôi đã thực hiện trước khi tôi đưa ra ý tưởng hơi xa, miễn là Mô hình không phụ thuộc vào bất cứ điều gì quan trọng như thế nào / nơi nó được truy cập? Tôi chưa quyết định cách tiếp cận nào tôi sẽ thực hiện cho sự phát triển tiếp theo của mình, nhưng điều này chắc chắn có ích.
Adam Westbrook

1

Một điều khác cần xem xét là bạn dường như đã tự động tải user_modelinvoice_modelcho phép chế độ xem truy cập chúng. Để điều này hoạt động một cách đáng tin cậy, bạn có thể tự động tải tất cả các mô hình của mình (vì $this->load->model()chỉ nhìn sai trong chế độ xem, không phải vậy ...)

Làm điều này một cách không cần thiết làm chồng ngăn xếp của bạn bằng cách tải một loạt các thứ có thể không bao giờ được sử dụng. Một phần lý do để có nhiều mô hình là cho phép bạn đóng gói logic liên quan và chỉ tải những gì bạn cần cho một nhiệm vụ nhất định.

Điều này trông giống như CodeIgniter. Tôi đã thực hiện rất nhiều phát triển CI và tôi có thể chia sẻ từ kinh nghiệm cá nhân rằng bạn thực sự không muốn tự động tải nhiều hơn bạn thực sự phải làm. Hãy thử thêm $this->output->enable_profiler(TRUE);vào hàm tạo của trình điều khiển và fiddle với tự động tải (bao gồm cả trình trợ giúp như database): bạn có thể sẽ thấy một sự thay đổi đáng kể về thời gian tải và thực thi, nhưng đặc biệt là trong cấp phát bộ nhớ.


1
Điểm hay, bạn nói đúng là dựa trên CI, mặc dù tôi đã xóa một số cú pháp cụ thể cho rõ ràng. Tôi đã có thói quen 'tự động tải' mọi thứ vì phần lớn thời gian và lý do DRY, có vẻ hơi điên khi có nhiều điểm giống nhau load->modeltrong hầu hết các bộ điều khiển và phương pháp. Không sử dụng chức năng tự động tải thích hợp là một trong những điều tôi không thích nhất về khả năng tương thích ngược của CI, nhưng đó là một cuộc thảo luận hoàn toàn khác ...
Adam Westbrook

0

Câu trả lời ngắn gọn là hình thức mẫu mã của bạn là trực quan. Có vẻ như đây là một cách "dễ dàng trong tâm trí" để đi.


Vấn đề # 1

Của bạn ModelViewcác đối tượng sẽ được liên kết chặt chẽ.

Nếu bạn phải thêm hoặc loại bỏ các phương thức trong Model, thì bạn có thể phải thay đổi cho Viewphù hợp.

Về cơ bản, MVC được lấy từ các mẫu CommandObserver . Bạn muốn có một độc lập 'mẫu' được chế tác thông qua một giao diện / API rằng Controllercó thể móc vào (tức là đoàn).

Thông thường, điều này có nghĩa là tiêm Model và các Viewtrường hợp vào Controllervà lưu trữ chúng như một thuộc tính nói Controller. Sau đó, bằng cách sử dụng một phương thức của Controller(tức là một lệnh) làm vùng làm việc, truyền dữ liệu đến một View từ Model ( sau khi `Model đã hoàn thành cập nhật trạng thái ứng dụng ).

Truyền dữ liệu (mảng, đối tượng lặp lại, bất cứ điều gì) giữ cho khớp nối giữa ModelViewtrường hợp lỏng lẻo . Nếu bạn đưa Modelcá thể vào View, xem Vấn đề # 1 ở trên.

Hãy nhớ rằng, Viewscó thể là HTML, JSON, Text, XML, tiêu đề HTTP, YAML hoặc hầu hết mọi thứ, theo phương pháp chuyển trạng thái đại diện (REST) .

Vì vậy, chìa khóa để hiểu cách quản lý mối quan hệ giữa ModelViewslà xem mối quan hệ đó là gì, một-nhiều (có khả năng)! Đây chính xác là những gì mẫu Observer được thiết kế để thực hiện.

Mặc dù hầu hết các thiết lập chỉ có một chế độ xem được quan tâm tại một thời điểm, nhưng không có gì ngăn cản mẫu kiến ​​trúc MVC cập nhật nhiều chế độ xem cùng một lúc! Làm việc với các ứng dụng web CRUD truyền thống khiến mọi người suy nghĩ theo cách một đối một , nhưng đó là ví dụ nhỏ nhất về cách thức mô hình Observer có thể hoạt động ( một đối với nhiều người khác ).

Do đó, nếu bạn có một Modelvà nhiều Views, việc đau đầu tiềm năng của việc cập nhật tất cả Views'mã triển khai vì bạn đã thay đổi một cái gì đó trong Model'sAPI / phương thức giờ trở nên nghiêm trọng .

Truyền dữ liệu đến Views , không phải trường hợp Models .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.