文章目錄
將ViewModel的建立過程從Controller中分離到ModelBuilder中,本質上是為了職責的分離,也提高了Controller的可讀性。
通常的情況
使用MVC時,在Controller中,會包含很多用於建立ViewModel的代碼。
讓我們從一個例子開始。
假設我們有一個用於呈現填寫訂單的頁面(~\Order\FT-BJS-95486),對應的Action 如下:
public ActionResult Order(string productNo){ var p = ProductService.GetProduct(productNo); var model = new OrderModel { ProductNo = productNo, ProductName = p.ProductName, }; return View(model);}
其中OrderModel 這個ViewModel的定義為:
public class OrderModel { public string ProductNo { get; set; } public string ProductName { get; set; } public int Count { get; set; } public string Address { get; set; }}
接下來,為了接收使用者輸入的訂單資訊,我們可能會有這樣一個Action:
[HttpPost]public ActionResult Order(OrderModel model){ var p = ProductService.GetProduct(productNo); if(!ModelState.IsVaidate()) { // 這裡假設: // 1. ProductName並沒用通過hidden input的方式post回來 // 2. ProductNo 隨同其它使用者輸入資訊post回來 model.ProductName = p.ProductName; return View(model); } var model2 = new OrderConfirmModel { ProductNo = model.ProductNo, ProductName = p.ProductName, Count = model.Count, Address = model.Address, }; return View("OrderConfirm", model2);}
1. 問題
- 有些ViewModel的建立可能比較“複雜”,從閱讀Controller的角度,不是“主控制流程”
- ViewModel會在不同階段被建立出來,不同階段的建立過程,往往出現一些重複的代碼
2. 分析
在上述的例子中,雖然OrderModel本身的結構及建立過程都非常簡單,但我們依然可以識別出重複的部分:
var p = ProductService.GetProduct(productNo);model.ProductName = product.ProductName;
我們可以歸納出這些重複的部分,分屬於兩個ViewModel被建立的“階段”:
- Create
- Rebuild
我們據此抽象出IModelBuilder介面
public interface IModelBuilder<TViewModel>{ TViewModel Create(); TViewModel Rebuild(TViewModel model);}
3. 改造
我們來寫一個OrderModelBuilder,實現IModelBuilder介面
public class OrderModelBuilder : IModelBuilder<OrderModel>{ private string _productNo; private string _productName; public OrderModelBuilder(string productNo, string productName) { _productNo = productNo; _productName = productName; } public OrderModel Create() { var model = new OrderModel { ProductNo = _productNo, }; model = this.Rebuild(model); return model; } public OrderModel Rebuild(OrderModel model) { model.ProductName = _productName; return model; }}
用OrderModelBuilder來簡化OrderController
private OrderModelBuilder GetBuilder(string productNo){ var p = ProductService.GetProduct(productNo); var builder = new OrderModelBuilder(p); return builder;}public ActionResult Order(string productNo){ var builder = GetBuilder(productNo); var model = builder.Create(); return View(model);}[HttpPost]public ActionResult Order(OrderModel model){ if(!model.IsVaidate()) { var builder = GetBuilder(model.ProductNo); var model = builder.Rebuild(model); return View(model); } // 根據OrderModel建立OrderConfirmModel var builder2 = new OrderConfirmModelBuilder(model); var model2 = builder2.Create(); return View("OrderConfirm", model2);}
這樣,就解決了我們在第1節中提出的兩個問題。
此文介紹的內容,無關語言和平台。