MVC Model View Controller
Posted On Sunday, June 22, 2008 at at 3:22 PM by Unknown- Mấy tuần nay tôi đang tìm hiều về các pattern thiết kế giao diện và đã gặp nhiều vướng mắc. Một số đã tự giải quyết được, một số vẫn còn tồn đọng. Vì vậy tôi cũng muốn chia sẽ những gì mình đã tìm hiểu với mọi người. Tôi quyết định dịch và viết bài từ mô hình ra đời lâu nhất và được nhiều người biết đến nhất, đó là mô hình MVC. Ban đầu tôi đã định không tìm hiểu về MVC và đi vào những thiết kế mới nhất như MVP nhưng thực ra MVC vẫn còn rất phổ biến hiện nay. (Cám ơn Tính nai oan oan cho các thông tin về MVC và Monorail) Vì vậy, trong những loạt bài sau tôi sẽ viết nhiều về pattern đang phổ biến hiện nay như MVP và các ví dụ thực tế của nó. Phần lớn sẽ là bài dịch và sửa đổi cho dễ hiểu, hiện nay vẫn chưa đủ trình độ để sáng tạo cái gì cả.
- Có thể nói rằng các chương trình dù là Win Application hay Web Application đều gồm hai thành phần chính là giao diện và dữ liệu. Các ứng dụng chúng ta tạo ra sẽ đọc dữ liệu từ nơi lưu trữ và hiển thị lên cho người dùng thấy. Sau khi người sử dụng chương trình thao tác với ứng dụng và thay đổi giá trị dữ liệu, chương trình sẽ lưu các thay đổi đó xuống nơi lưu trữ. Do luồng thông tin chính của các ứng dụng sẽ truyền từ nơi lưu trữ lên trên phần hiển thị và ngược lại nên người có thể cho rằng nên có cách nào đó thiết kế hai thành phần dữ liệu và giao diện cùng với nhau để giảm thiểu việc coding và tăng performance. Dù không cố tình làm như vậy nhưng đa số những bạn mới viết chương trình cơ sở dữ liệu lần đầu tiên thường không biết nên sẽ làm theo cách này. Cách làm như vậy có một số vấn đề nghiêm trọng. Một trong các vấn đề đó là việc giao diện thường có xu hướng thay đổi nhiều hơn so với dữ liệu lưu trữ. Hơn nữa, những xử lý tính toán (business logic) trong chương trình cũng là một thành phần thường xuyên thay đổi trong suốt quá trình phát triển phần mềm. Nếu chương trình được xây dựng theo kiểu trộn lẫn code của các thành phần data access, business logic và presentation thì sẽ rất khó bảo trì sửa đổi cũng như khả năng sử dụng lại. Chính vì mục đích tăng tính độc lập giữa các thành phần trong ứng dụng và để giải quyết những trở ngại trên, người ta đã nghĩ ra nhiều mô hình và cách thiết kế ứng dụng rất hiệu quả. Kể từ những năm 70, mô hình MVC được nghĩ ra để giải quyết một số vấn đề trên.
Đặt vấn đề:
- Khi lần đầu tiên viết chương trình đọc dữ liệu từ database và hiển thị lên form, tôi đã viết chương trình kiểu gom chung phần xử lý giao diện và truy xuất dữ liệu làm một. Có nghĩa là tôi tạo ra câu query sql ngay trong code của lớp giao diện. Cách làm này rất không hợp lý vì khi sửa đổi cấu trúc bảng trong cơ sở dữ liệu thì câu query sql sẽ cần phải đổi, dẫn đến phải sửa lớp giao diện. Khi cần đổi database khác thì gần như phải viết lại từ đầu. Như vậy gom chung giữa giao diện và dữ liệu là không nên, và ai cũng biết điều đó.
- Liệu có một cách nào chúng ta có thể chia nhỏ chương trình thành nhiều module để tiện thay đổi, bảo trì?
Giả sử người ta có các yêu cầu sau:
- Giao diện của ứng dụng có xu hướng thay đổi nhiều hơn là những thay đổi business logic của chương trình, đặt biệt đối với những ứng dụng Web. Ví dụ như cùng một trang Web hiển thị sản phẩm có thể sẽ được yêu cầu thay đổi nhiều lần về cách bố trí sản phẩm, màu sắc bố cục trong khi cách để lấy thông tin sản phẩm từ database sẽ không cần sửa đổi. Hơn nữa, một trong những tiện lợi của ứng dụng Web là người ta có thể thay đổi giao diện vào bất cứ lúc nào mà không cần người dùng phải install cài đặt gì cả. Nếu như những đoạn code xử lý giao diện và xử lý business logic bên trong chương trình được viết chung với nhau, bạn sẽ phải thay đổi những lớp dùng để xử lý business logic mỗi khi cần thay đổi giao diện. Mà khi xử lý business logic của ứng dụng bị thay đổi thì có thể sẽ gây ra các lỗi không mong muốn nên phải test mọi thứ lại từ đầu cho dù đó chỉ là một thay đổi nhỏ về giao diện. Như vậy ta có một nhu cầu về việc tách riêng giữa giao diện và các xử lý business logic.
- Trong một số ứng dụng, chương trình sẽ hiển thị cùng một dữ liệu bằng nhiều cách khác nhau. Ví dụ như chúng ta cần làm một loạt các biểu đồ khác nhau hiển thị giá chứng khoán, các biểu đồ này được hiển thị cùng lúc. Nếu người dùng thay đổi dữ liệu trên một màn hình nào đó thì hệ thống phải cập nhật thay đổi đó trên các màn hình còn lại. Ta có một nhu cầu về tự cập nhật giao diện khi có những thay đổi trong dữ liệu.
- Để thiết kế giao diện HTML đẹp và hiệu quả cần những kĩ thuật đặt biệt, có khi cả năng khiếu về mĩ thuật mà không phải một lập trình viên nào cũng có được. Vì vậy trong những dự án lớn thường có những người design giao diện riêng và công việc của họ chỉ là thiết kế layout, còn lập trình viên sẽ thực hiện các xử lý business logic của ứng dụng. Do đó nhu cầu cho việc tách rời phần design giao diện và phần lập trình được đặt ra để tăng hiệu quả cho quá trình làm phần mềm.
- Có một yêu cầu khác được đặt ra như sau: những thao tác trên giao diện thông thường sẽ gồm có hai phần: hiển thị và cập nhật. Thành phần hiển thị sẽ lấy dữ liệu từ nơi lưu trữ, định dạng lại nếu cần thiết và hiển thị lên màn hình. Khi người sử dụng thực hiện một số thao tác, những gì thay đổi sẽ được thành phần cập nhật gọi thành phần xử lý business logic để cập nhật các thay đổi đó xuống nơi lưu trữ. Như vậy thành phần hiển thị sẽ tự nó thực hiện việc lấy thông tin, trong khi những thao tác của người dùng sẽ được xử lý bởi một thành phần khác.
- Trong các ứng dụng Web, khi bạn click vào một link trên 1 trang, một thao tác ứng với link đó sẽ được thực hiện đồng thời một trang mới sẽ được hiển thị. Trong nhiều trường hợp, trang web cần hiển thị sau cùng sẽ không liên quan trực tiếp đến thao tác được gọi khi click vào link ở trang trước. Ví dụ: trong những trang Web mua bán trực tuyến, khi muốn xem danh sách những món hàng mình muốn mua trước khi thanh toán, bạn sẽ click vào phần giỏ hàng. Một danh sách những món hàng sẽ hiện ra kèm với các link hoặc button xóa chúng khỏi giỏ hàng. Nếu bạn đổi ý và muốn bỏ đi một món nào đó thì bạn sẽ click vào link hoặc button tương ứng. Sau đó, giỏ hàng sẽ lại hiện ra với danh sách những món hàng mới mà không có món bạn vừa xóa. Vì vậy, ứng dụng phải hiển thị lại cùng 1 trang với cùng một danh sách nào đó sau khi thực hiện hai thao tác khác hẳn nhau trong cùng một HTTP request. Vậy có một yêu cầu là nhiều xử lý phức tạp sẽ được thực hiện trong cùng một request.
- Ngày nay, giao diện của một ứng dụng nên được độc lập với thiết bị. Nếu bạn muốn ứng dụng Web của mình có thể được hiển thị nhanh và đẹp trên các thiết bị di dộng thì bạn phải sửa đổi nhiều ở phần giao diện và chắc chắn là những business logic sẽ không cần thay đổi gì cả. Một sự tách biệt rõ ràng giữa hai thành phần này sẽ giúp bạn đạt được yêu cầu đó vài giảm thiểu những rủi ro khi phải thay đổi business logic do sai lầm khi thiết kế lúc đầu. Vậy dẫn đến yêu cầu về thiết kế ứng dụng để dễ dàng hỗ trợ nhiều dạng thiết bị khác nhau chứ không riêng gì máy tính.
- Và cuối cùng, để phần mềm của bạn có thể được test một cách toàn diện đôi khi không khả thi và rất mất thời gian. Hiện nay người ta có thể sử dụng Unit Test để test các lớp business logic nhanh chóng chính xác và tự động trong hầu hết trường hợp. Vì thế càng làm cho những xử lý tách rời khỏi phần giao diện sẽ giúp chương trình của bạn dễ viết code test hơn. Vậy yêu cầu thiết kế ứng dụng cho dễ test bằng code cũng được đặt ra.
MVC sẽ đạt được mọi yêu cầu trên:
- Mẫu thiết kế Model-View-Controlller (MVC) tách rời phần dữ liệu domain, module hiển thị và những xử lý thao tác của người dùng thành ba nhóm lớp (class) riêng biệt:
Model: là những gì liên quan đến dữ liệu của ứng dụng. Model sẽ chịu trách nhiệm thao tác trực tiếp với database như truy xuất, cập nhật, thêm mới. Model sẽ lấy thông tin và trả về cho View, nó cũng sẽ chịu trách nhiệm thông báo cho Controller những thay đổi dữ liệu nếu có. Bạn có thể xem Model bao gồm các lớp DAL (Data Access Layer) và các lớp Domain.
View: View sẽ chịu trách nhiệm hiển thị thông tin như tên của nó. Ta có thể xem View như các trang web, hoặc các form trong ứng dụng windows.
Controller: là những lớp sẽ lắng nghe những thao tác chuột và bàn phím từ người dùng, nó sẽ tác động đến Model và View để thay đổi khi cần thiết.
Hình dưới mô tả mối quan hệ giữa Model, View và Controller, Model sẽ không biết gì về View và
Controller.
Hình: MVC Class Structure
- Theo như hình trên thì ta thấy cả View và Controller đều phụ thuộc và có thể gọi đến Model. Tuy nhiên, Model lại hoàn toàn độc lập với View và Controller. Điều này là một trong những lợi ích chính của mô hình MVC khi tách rời các thành phần Model View và Controller. Sự độc lập của Model giúp chúng ta build và viết code test cho nó mà không ảnh hưởng hoặc phụ thuộc đến những lớp hiển thị. Ngoài ra, sự tách rời View và Controller ra hai nhóm lớp như trên là một thuận lợi thứ hai đối với những ứng dụng có nhiều người dùng. Ví dụ như trong một số cách làm, người ta có thể lập trình phần kiểm tra quyền (Role) ngay trong phần xử lý giao diện. Khi theo cách làm MVC, người ta sẽ phải tách riêng phần kiểm tra quyền ra khỏi phần hiển thị và nó hoàn toàn thuận lợi khi cần sửa đổi hoặc thêm những trang mới.
Những lợi ích về test khi áp dụng MVC
- Sự dễ dàng trong viết code test là một thuận lợi khi áp dụng MVC. Test những component của chương trình trở nên rất khó khăn khi chúng phụ thuộc chặt chẽ vào nhau, đặc biệt đối với những thành phần giao diện. Để test giao diện của một phần mềm, tất nhiên bạn phải qua các bước cài đặt và đôi khi điều đó trở nên rất mất thời gian khi chỉ để test một chức năng đơn giản. Tệ hơn khi xảy ra lỗi, chúng ta sẽ rất khó để phát hiện lỗi ở phần nào. Đó là lý do tại sao chia nhỏ các thành phần chức năng là một trong những chiều hướng chính của các thiết kế quan trọng. MVC chia nhỏ các vấn đề như lưu trữ, hiển thị và cập nhật dữ liệu thành 3 nhóm components, những component này có thể được test độc lập với nhau.
- Ngoài vấn đề về sự phụ thuộc, giao diện của phần mềm cũng rất phức tạp khi muốn test. Người ta thường sử dụng người thật để test giao diện, hoặc sẽ phải viết những script test để giả lập những thao tác của con người. Để viết những script này thường rất mất thời gian và phức tạp. MVC KHÔNG giải quyết được vấn đề về test giao diện, NHƯNG nó tách rời phần dữ liệu Model ra khỏi những xử lý hiển thị và cho phép MODEL có thể được test độc lập với phần hiển thị và điều đó sẽ giảm thiểu những test case liên quan đến giao diện.
Ý kiến của Nguyễn Thoại:
- Tôi đã không dịch và đưa vào những dạng biến đổi của mẫu MVC vào bài này vì không muốn các bạn cảm thấy rối thêm, cũng không đưa vào những lợi ích và giới hạn của MVC. Lợi ích thì tất nhiên đã được đề cập tới ở trên nên cũng không cần tổng kết lại làm gì, còn giới hạn chính là tính phức tạp. Cũng như những bài viết trước, các Pattern luôn phức tạp nhưng khi chịu khó một chút thì về sau sẽ được những lợi ích lớn.
- Các bạn có thể đặt câu hỏi: áp dụng MVC vô ASP.NET như thế nào. Có ví dụ code sample nào không. Xin thưa là có trang ví dụ ở đây, nhưng cá nhân tôi vẫn còn nghi ngờ tính đúng đắn của nó. Sắp tới, tôi sẽ viết thêm một số bài nữa liên quan đến việc áp dụng MVC trong.NET để tìm hiểu những vấn đề tôi còn nghi ngờ. Trong bài viết này không có ví dụ vì tôi sẽ dành phần code sample cho các bài sau. Hi vọng qua bài dịch này các bạn có được khái niệm MVC là cái gì, và lợi ích của nó như thế nào và khoan hãy nghĩ đến cách áp dụng. Cũng giống như những pattern khác (ở các bài viết sau), MVC được nghĩ ra với mục đích tách rời các thành phần quan trọng trong ứng dụng để tăng tính dễ bảo trì, dễ test tự động và khả năng sử dụng lại. Cùng một mục đích như vậy nhưng các mẫu pattern khác như MVP sẽ có cách thực hiện và cách cài đặt khác.
Liệu mô hình ASP.NET của Microsoft với các trang aspx và code behind tách rời có phải là một implement MVC? Ở bài sau tôi sẽ trả lời câu hỏi đó và giới thiệu khái quát về một framework MVC Framework cho ASP.NET.
Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!
Mình mới học mvc và thấy nó có nhiều tương đồng với mô hình 3 lớp. Điểm khác biệt mình thấy là lớp prensentation sẽ tách thành phần xử lý ra (view sẽ không có xử lý).
Quả thực rất rối. Bạn có thể viết 1 ứng dụng để minh họa kỹ thuật dùng mvc khác thế nào so với 3 lớp không? Cám ơn bạn nhiều.