6

Bản chất của câu hỏi của tôi là làm thế nào để soạn các đối tượng này (xem bên dưới) một cách hợp lý với MVC3 và Ninject (mặc dù tôi không chắc chắn DI nên đóng một vai trò trong giải pháp). Tôi không thể tiết lộ chi tiết thực sự của dự án của tôi nhưng đây là một phép tính xấp xỉ minh họa vấn đề/câu hỏi. Các câu trả lời trong VB hoặc C# được đánh giá cao!Soạn thảo các đối tượng đa hình trong dự án ASP.NET MVC3

Tôi có một số sản phẩm khác nhau với các thuộc tính thay đổi rộng rãi nhưng tất cả chúng đều cần được thể hiện trong danh mục. Mỗi lớp sản phẩm có một bảng tương ứng trong cơ sở dữ liệu của tôi. Một mục danh mục có một số thuộc tính cụ thể để trở thành mục nhập danh mục và do đó có bảng riêng. Tôi đã định nghĩa một giao diện cho các mục danh mục với mục đích gọi thuộc tính DescriptionText sẽ cung cấp cho tôi các kết quả rất khác nhau dựa trên loại bê tông cơ bản.

Public Class Clothing 
    Property Identity as Int64 
    Property AvailableSizes As List(Of String) 
    Property AvailableColor As List(Of String) 
End Class 

Public Class Fasteners 
    Property Identity as Int64 
    Property AvailableSizes As List(Of String) 
    Property AvailableFinishes As List(Of String) 
    Property IsMetric As Boolean 
End Class 

Public Interface ICatalogEntry 
    Property ProductId as Int64 
    Property PublishedOn As DateTime 
    Property DescriptionText As String 
End Interface 

Cho rằng DescriptionText là lớp trình bày quan tâm Tôi không muốn triển khai giao diện ICatalogEntry trong các lớp sản phẩm của mình. Thay vào đó, tôi muốn ủy thác cho một số loại định dạng.

Public Interface ICatalogEntryFormatter 
    Property DescriptionText As String 
End Interface 

Public Class ClothingCatalogEntryFormatter 
    Implements ICatalogEntryFormatter 

    Property DescriptionText As String 
End Class 

Public Class FastenerCatalogEntryFormatter 
    Implements ICatalogEntryFormatter 

    Property DescriptionText As String 
End Class 

Trong một bộ điều khiển ở đâu đó sẽ có mã như thế này:

Dim entries As List(Of ICatalogEntry) 
        = catalogService.CurrentCatalog(DateTime.Now) 

Trong một cái nhìn ở đâu đó sẽ có mã như thế này:

<ul> 
@For Each entry As ICatalogEntry In Model.Catalog 
    @<li>@entry.DescriptionText</li> 
Next 
</ul> 

Vậy câu hỏi là những gì làm nhà thầu trông như thế nào? Làm thế nào để thiết lập nó để các đối tượng thích hợp được khởi tạo ở đúng nơi. Có vẻ như Generics hoặc DI có thể giúp đỡ với điều này nhưng tôi dường như có một khối tâm thần. Ý tưởng duy nhất mà tôi đưa ra là để thêm một tài sản ProductType để ICatalogEntry và sau đó thực hiện một nhà máy như thế này:

Public Class CatalogEntryFactory 
    Public Function Create(catEntry as ICatalogEntry) As ICatalogEntry 
     Select Case catEntry.ProductType 
     Case "Clothing" 
      Dim clothingProduct = clothingService.Get(catEntry.ProductId) 
      Dim clothingEntry = New ClothingCatalogEntry(clothingProduct) 
      Return result 
     Case "Fastener" 
      Dim fastenerProduct = fastenerService.Get(catEntry.ProductId) 
      Dim fastenerEntry = New FastenerCatalogEntry(fastenerProduct) 
      fastenerEntry.Formatter = New FastenerCatalogEntryFormatter 
      Return fastenerEntry 
    ...  
    End Function 
End Class 

Public ClothingCatalogEntry 
    Public Sub New (product As ClothingProduct) 
     Me.Formatter = New ClothingCatalogEntryFormatter(product) 
    End Sub 

    Property DescriptionText As String 
     Get 
      Return Me.Formatter.DescriptionText 
     End Get 
    End Property 
End Class 

...FastenerCatalogEntry is omitted but you get the idea... 

Public Class CatalogService 
    Public Function CurrentCatalog(currentDate as DateTime) 
     Dim theCatalog As List(Of ICatalogEntry) 
            = Me.repository.GetCatalog(currentDate) 

     Dim theResult As New List(Of ICatalogEntry) 

     For Each entry As ICataLogEntry In theCatalog 
      theResult.Add(factory.Create(entry)) 
     Next 

     Return theResult 
    End Function 
End Class 

IMHO, tôi không thực sự nhận được bất kỳ mùi tắt mã này khác hơn là phải thay đổi nhà máy cho mỗi lớp sản phẩm mới đi kèm. Tuy nhiên, ruột của tôi nói rằng đây là cách làm cũ và ngày nay DI và/hoặc generics có thể làm điều này tốt hơn. Các đề xuất về cách xử lý này được đánh giá cao (như các đề xuất về tiêu đề tốt hơn ...)

Trả lời

1

Vì vậy, thực hiện một vài thay đổi nhỏ, tôi đã làm việc này bằng cách sử dụng tiện ích mở rộng Nhà máy Ninject. Thay đổi lớn nhất là các thực thể của tôi có đủ thông tin để hiển thị một trong hai loại (quần áo hoặc ốc vít trong ví dụ giả mạo của tôi) nếu mặt hàng thực sự là quần áo thì các thuộc tính cụ thể của fastener sẽ là rỗng và ngược lại.

Public Interface IDescribable 
    ReadOnly Property DescriptionText As String 
End Interface 

Public Enum ProductType 
    CLOTHING 
    FASTENER 
End Enum 

Public Interface ICatalogEntry 
    Inherits IDescribable 
    ReadOnly Property ProductId As Int64 
    ReadOnly Property PublishedOn As DateTime 
    ReadOnly Property ProductType As ProductType 
End Interface 

Public Class CatalogEntryEntity 
    Public Property ProductId As Long 
    Public Property ProductType As ProductType 
    Public Property PublishedOn As Date 
    Public Property DescriptionText As String 
    Public Property Color As String 
    Public Property Finish As String 
    Public Property IsMetric As Boolean 
End Class 

Sau đó, với điều này ở nơi tôi có thể xác định dịch vụ Danh mục của tôi như sau:

Public Class CatalogService 
    Private ReadOnly _factory As ICatalogEntryFactory 
    Private ReadOnly _repository As CatalogRepository 

    Public Sub New(entryFactory As ICatalogEntryFactory, repository As CatalogRepository) 
     Me._factory = entryFactory 
     Me._repository = repository 
    End Sub 

    Public Function CurrentCatalog(currentDate As DateTime) As List(Of ICatalogEntry) 
     Dim items = Me._repository.GetCatalog() 
     Return (From item In items Select _factory.Create(item.ProductType.ToString(), item)).ToList() 
    End Function 
End Class 

Public Interface ICatalogEntryFactory 
    Function Create(bindingName As String, entity As CatalogEntryEntity) As ICatalogEntry 
End Interface 

Ninject sẽ cung cấp cho các nhà máy giả sử tôi thiết lập các ràng buộc như thế này (đó là tuyệt vời!):

theKernel.Bind(Of ICatalogEntry)().To(Of ClothingCatalogEntry)().Named("CLOTHING") 
theKernel.Bind(Of ICatalogEntry)().To(Of FastenerCatalogEntry)().Named("FASTENER") 
theKernel.Bind(Of ICatalogEntryFactory)().ToFactory(Function() New UseFirstParameterAsNameInstanceProvider()) 

Tôi đã bỏ qua FastenerCatalogEntry để ngắn gọn; the ClothingCatalogEntry giống như sau:

Public Class ClothingCatalogEntry 
    Public Sub New(ByVal entity As CatalogEntryEntity) 
... 

Đó là this post đã giúp tôi tìm hiểu điều này nhất. Tôi đã sử dụng UseFirstParameterAsNameInstanceProvider chính xác như được hiển thị ở đó.

1

Tôi thích chỉ sử dụng hàm tạo mặc định trên mô hình cho chế độ xem và điền chúng thông qua Automapper.

tôi sẽ có một mô hình quan điểm như thế này:

public interface IHasDescription 
{ 
    public string DescriptionText { get; set; } 
} 

public class ViewModelType : IHasDescription 
{ 
    [DisplayName("This will be rendered in the view")] 
    public string SomeText { get; set; } 

    public string DescriptionText { get; set; } 
} 

Và tôi có một mô hình từ DAL như thế này:

public class DALModelType 
{ 
    public string SomeText { get; set; } 
} 

Vì vậy, bạn có một cái gì đó như thế này trong điều khiển của bạn:

var dalModel = someRepository.GetAll(); 
var viewModel = Mapper.Map<DALModelType, ViewModelType>(dalModel); 

Và bạn có mã thiết lập Automapper trong một số tệp. Bằng cách này, bạn chỉ có mã chuyển đổi ở một nơi thay vì trong nhiều phương pháp/bộ điều khiển. Bạn có một custom resolver trong đó sử dụng tiêm phụ thuộc (thay vì() => new CustomResolver()) và điều này sẽ nhà logic của bạn để nhận được văn bản hiển thị.

Mapper.CreateMap<IHasDescription, ViewModelType>() 
    .ForMember(dest => dest.DescriptionText, 
       opt => opt.ResolveUsing<CustomResolver>().ConstructedBy(() => new CustomResolver())); 

Không chắc nếu điều này làm việc với các công việc của bạn nhưng nó nên có thể giúp bạn có được những gì bạn muốn.

+0

Trình phân giải tùy chỉnh xử lý thực tế rằng nhiều hơn một lớp bản đồ đến cùng một giao diện? Đó là những gì đang đẩy tôi đến lớp nhà máy trong câu hỏi của tôi và đó là những gì tôi không thoải mái nhất và hoàn toàn không rõ ràng làm thế nào để thoát khỏi. – schmidlop

+0

Ok, bây giờ tôi đã đọc liên kết bạn đã cung cấp, tôi đã kết luận rằng tôi nên mong đợi hợp lý vùng chứa DI của tôi (Ninject) để có một số câu trả lời cho trường hợp này. Hơn nữa nó có vẻ như nó không và tôi cần ràng buộc theo ngữ cảnh https://github.com/ninject/ninject/wiki/Contextual-Binding và tôi có thể cần điều này là tốt: https://github.com/ninject/ninject.extensions. nhà máy/wiki – schmidlop

+0

Vâng, điều đó thực sự nên giải quyết vấn đề của bạn. Trong khởi tạo ninject của bạn, bạn sẽ có thể tải từ một tập tin tài nguyên. –

Các vấn đề liên quan