sch*_*lop 6 asp.net-mvc dependency-injection object-composition ninject-extensions
我的问题的本质是如何用MVC3和Ninject以合理的方式组合这些对象(见下文)(尽管我不确定DI应该在解决方案中发挥作用).我无法透露我的项目的真实细节,但这是一个近似,说明了问题/问题.在VB或C#中的答案表示赞赏!
我有几种不同的产品,具有各种各样的特性,但它们都需要在目录中表示.每个产品类在我的数据库中都有一个对应的表.商品具有一些特定于商品的属性,因此拥有自己的表.我已经为目录条目定义了一个接口,其目的是调用DescriptionText属性将根据底层的具体类型给出非常不同的结果.
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
Run Code Online (Sandbox Code Playgroud)
鉴于DescriptionText是表示层关注的问题,我不想在我的产品类中实现ICatalogEntry接口.相反,我想将其委托给某种格式化程序.
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
Run Code Online (Sandbox Code Playgroud)
在一个控制器的某个地方会有这样的代码:
Dim entries As List(Of ICatalogEntry)
= catalogService.CurrentCatalog(DateTime.Now)
Run Code Online (Sandbox Code Playgroud)
在某个地方的视图中会有这样的代码:
<ul>
@For Each entry As ICatalogEntry In Model.Catalog
@<li>@entry.DescriptionText</li>
Next
</ul>
Run Code Online (Sandbox Code Playgroud)
所以问题是构造函数是什么样的?如何设置它以便在适当的位置实例化适当的对象.看起来像仿制药或DI可能有助于此,但我似乎有一个心理障碍.我想出的唯一想法是将一个ProductType属性添加到ICatalogEntry,然后实现这样的工厂:
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
Run Code Online (Sandbox Code Playgroud)
恕我直言,除了必须为每个新产品类别更改工厂外,我并没有真正得到这些代码的任何气味.然而,我的直觉说这是旧的做事方式,而现在DI和/或仿制药可以更好地做到这一点.关于如何处理这个问题的建议非常感谢(关于更好标题的建议......)
因此,我做了一些小改动,使用 Ninject Factory 扩展使其正常工作。最大的变化是我的实体有足够的信息来显示任一类型(在我设计的示例中为衣服或紧固件),如果该项目实际上是衣服,则紧固件特定属性将为空,反之亦然。
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
Run Code Online (Sandbox Code Playgroud)
然后,我可以定义我的目录服务,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
假设我像这样设置绑定,Ninject 将提供工厂(这太棒了!):
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())
Run Code Online (Sandbox Code Playgroud)
为了简洁起见,我省略了 FastenerCatalogEntry;ClothingCatalogEntry 是这样的:
Public Class ClothingCatalogEntry
Public Sub New(ByVal entity As CatalogEntryEntity)
...
Run Code Online (Sandbox Code Playgroud)
这篇文章对我解决这个问题最有帮助。我完全按照此处所示使用 UseFirstParameterAsNameInstanceProvider 。
| 归档时间: |
|
| 查看次数: |
192 次 |
| 最近记录: |