2013-07-19 79 views
3

我是ASP.NET MVC的新手,我被困在一個點上。我正在分類網站上工作。我的情況是,我有許多類別,用戶可以在其中發佈廣告,並且每個廣告類別具有不同的視圖。我創建了一個控制器動作像ASP.NET MVC有條件的ViewModel抽象

public ActionResult PostAd(string CategoryName, string SubCategoryName) 
{ 
     if(categoryName == "Vehicle" && SubCategoryName == "Cars") 
     { 
      var model = new CarAdViewModel(); 

      // set CarAdViewModel properties... 

      return View("CarAdCreateView", model); 
     } 
     else if(categoryName == "Vehicle" && SubCategoryName == "Bikes") 
     { 
      var model = new BikeAdViewModel(); 

      // set BikeAdViewModel properties... 

      return View("BikeAdViewModel", model); 
     } 
     else if(categoryName == "Property" && SubCategoryName == "RentHouse") 
     { 
      var model = new RentHouseAdViewModel(); 

      // set RentHouseAdViewModel properties... 

      return View("RentHouseAdViewModel", model);     
     } 
     else................... so on and so on 
} 

我的問題是我有大量的類別和子類別幾乎60 +。如果我繼續爲60多個類別和子類別編碼,我的PostAd方法將會爆炸並變得難以管理。

請告訴我一些最佳實踐或模式,可以讓我擺脫這個問題。

+0

你真的確認你需要爲每個類別有不同的看法?你爲什麼這麼認爲? –

+0

@MystereMan我的所有廣告字段都與CarAd的不同:BodyType,Make,Model,MechanicalCondition等,RentHouse有:NumberOfRooms,NumberofBathroom,IsFurnished,HasAttachedBath等等。告訴我是否有其他方法? –

+0

視圖和操作方法需要根據其邏輯進行更改,而不一定基於數據或字段。你可以根據集合類型在視圖中渲染不同的字段..你應該看看EditorTemplates http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/ –

回答

3

不幸的一個,一些你在做什麼,是無法避免的。需要基於類別進行某種形式的模型和視圖選擇。

使用工廠模式。創建一個基類:

public abstract class BaseCategory 
{ 
    public abstract string GetViewName(); 
    public abstract Object CreateModelFromFormData(); 
} 

對於每個類別,創建從BaseCategory衍生的子類,並實現抽象功能。

在你的行動,做到以下幾點:

public ActionResult PostAd(string categoryName, string subCategoryName) 
{ 
    BaseFactory factory; 
    if (categoryName == "Vehicle") 
    { 
    if (subCategoryName == "Cars") 
    { 
     factory = new CarsFactory(); 
    } 
    else ... 
    } 
    else ... 

    return View(factory.GetViewName(), factory.CreateModelFromFormData()); 
} 

我對這個模式的幾個原因:

  1. 我故意使用if/else爲工廠選擇。您的控制器將被創建併爲每個操作調用重新創建。因此,預先填充列表會不斷地和不必要地爲不會被選中的類別創建對象。簡單的if/else會更有效率。如果你想阻止if/else,你可以把你的工廠放在Dictionary並根據類別進行選擇,但這將是很多不必要的構造函數操作。

  2. 我做了CreateModelFromFormData函數,因爲我假設您需要從發佈的表單數據中複製數據。這可能需要傳入數據,但我離開了無參數的函數。

  3. 我使用了基類/派生類,因爲表單數據的複製可能需要根據正在創建的模型和表單數據發佈來自定義。另外,保存到持久性存儲(文件或數據庫)也可以是特定類別的。

1

這將是一些可能的解決方案

public class PostAdData 
{ 
    public string CategoryName; 
    public string SubCategoryName; 
    public string ViewName; 
    public Type Model; 
} 

public class PostController : Controller 
{ 
    private readonly List<PostAdData> _theData; 

    public HomeController() 
    { 
     _theData = InitializeData(); 
    } 


    public ActionResult PostAd(string categoryName, string subCategoryName) 
    { 
     var data = _theData.FirstOrDefault(c => c.CategoryName == categoryName && c.SubCategoryName == subCategoryName); 
     if (data != null) 
     { 
      var model = Activator.CreateInstance(data.Model); 
      return View(data.ViewName, model); 
     } 
     return View("Error"); 
    } 

    [NonAction] 
    public List<PostAdData> InitializeData() 
    { 
     var result = new List<PostAdData> 
         { 
          new PostAdData 
           { 
            CategoryName = "Vehicle", 
            SubCategoryName = "Cars", 
            ViewName = "CarAdCreateView", 
            Model = typeof (CarAdViewModel) 
           } 
         }; 
     return result; 
    } 
} 
+0

使您的'_theData'靜態並填充到靜態構造函數中。否則,它將被填充並重新填充每個動作調用。 –

+0

沒錯。謝謝Matt –

+0

@MattHouser這是一個很好的觀點。 –

1

您應該使這個數據驅動。您創建一個查找表,其中包含類別和子類別的複合主鍵。然後它有一個包含View的表格。然後,您只需爲每個類別/子類別/視圖組合添加行。

如果你絕對不想要數據庫,那麼你可以使用一個簡單的哈希集或字典。

var views = new Dictionary<Tuple<string,string>,string>(); 

views.Add(new Tuple<string,string>("Vehicle", "Cars"), "CarAdCreateView"); 

然後在您的PostAd中,您只需查找正確的視圖。

+0

我會更喜歡數據庫方法,但我失去了做什麼。 –

1

www上的多麼美麗的解決方案。ASP.NET我的問題,這裏是鏈接:http://forums.asp.net/t/1923868.aspx/1?ASP+NET+MVC+Conditional+ViewModel+Abstraction

編輯:

我的代碼是:

public class AdsController : Controller 
{ 
    private readonly IAdService _adService; 
    public AdsController(IAdService adService) 
    { 
     _adService = adService; 
    } 

    public ActionResult PostAd(string Category, string SubCategory) 
    { 
     //Here I will call 
     var strategy = GetStrategy(CategoryName, SubCategoryName); 
     strategy.FillModel(_adService); 
     return View(strategy.ViewName, strategy.Model); 
    } 
} 
+0

這種方法的問題在於它會在每個操作調用中創建對象以尋找合適的類。事實上,我懷疑績效會比@ abbas-amiri的方法更糟,因爲它會做額外的「搜索課程」。是的,它很漂亮,但是你會爲它贏得性能。如果你打算繼續使用這個解決方案,那麼至少要「發現」這些類並緩存它們。 –

+0

我知道我會失去一些GetStrategy()方法的性能,但爲什麼它會在每個動作調用中創建這些對象? –

+1

作爲'GetStrategy'的一部分,隱藏在LINQ語句中的是Activator.CreateInstance,它將創建它找到的對象的一個​​實例,然後將你想要的類別與該對象內部的類別進行比較。這些對象被創建,比較然後銷燬(如果它不是正確的)。您爲每個PostAd調用調用'GetStrategy',因此它會爲每個PostAd創建,比較和銷燬許多對象。 –