6

私の質問の本質は、MVC3とNinjectを使ってこれらのオブジェクトを以下のように構成する方法です(DIはソリューションで役割を果たすべきかどうかわかりませんが)。私は私のプロジェクトの実際の詳細を明らかにすることはできませんが、ここに問題/質問を示す近似があります。 VBまたはC#での回答が高く評価されています。ASP.NET MVC3プロジェクトでポリモーフィックオブジェクトを作成する

私は広範囲に変化する特性を持ついくつかの異なる製品を持っていますが、それらのすべてはカタログで表現する必要があります。各製品クラスには、データベースに対応するテーブルがあります。カタログ・エントリーには、カタログ・エントリーに固有のプロパティーがいくつかあり、結果的に独自の表があります。私は、DescriptionTextプロパティを呼び出すと、根底にある具体的な型に基づいて非常に異なる結果が得られるという意図で、カタログエントリ用のインターフェイスを定義しました。 DescriptionTextは、私は私の製品クラスでICatalogEntryインターフェイスを実装する必要はありませんプレゼンテーション層の関心事であることを考えると

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 

。代わりに私はそれをある種のフォーマッタに委ねたい。コントローラで

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 

どこかでこのようなコードがあるでしょう。どこかのようなコードがあるでしょう見解で

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

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

そこで問題は、何をすべきかですコンストラクタはどのように見えますか?適切なオブジェクトが適切な場所にインスタンス化されるように設定する方法。ジェネリックのように見えるかもしれないし、あるいはDIがこれを助けるかもしれないが、私は精神的なブロックを持っているようだ。私が作ってみただけな考え方はICatalogEntryにでProductTypeプロパティを追加して、このような工場を実装することです:

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 

私見を、私は本当にすべてを変更すること以外に、このコードをオフににおいが届かないのです来るべき新製品クラスのための工場。しかし、私の腸は、これは物事を行う古い方法であり、今日ではDIやジェネリック医薬品がこれをより良くすることができると言います。

答えて

1

私はこれを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 

は、その後の場所でこれで私は私のカタログサービスを定義することができます。

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工場提供します。このように私のセットアップにバインディングを想定した(素晴らしいです!):

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()) 

簡潔にするためにFastenerCatalogEntryを省略しました。 ClothingCatalogEntryはこのようなものです:

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

それは私にこれを理解するために最も役立ったものthis postました。そこに示すようにUseFirstParameterAsNameInstanceProviderを使用しました。

1

私はちょうどビューのモデルでデフォルトのコンストラクタを使用し、Automapperを介してそれらを移入するのが好きです。

私はこのようなビューモデルだろう:

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; } 
} 

をそして私はこのようなDALからのモデルがあります:

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

だから、あなたはあなたのコントローラ内でこのような何かを持っている:

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

また、Automapperの設定コードがあるファイルにあります。この方法では、複数のメソッド/コントローラではなく、1つの場所にのみコンバージョンコードがあります。 (()=> new CustomResolver()の代わりに)依存性注入を使用するcustom resolverがあり、これは表示テキストを取得するロジックを格納します。

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

これはあなたのワークフローで動作しますが、何をしたいあなたを得ることができる必要がありますかどうかわかりません。

+0

したがって、カスタムリゾルバは、複数のクラスが同じインターフェイスにマップされているという事実を処理しますか?それが私の疑問の中で私を工場の階級に押し込んでいるのです。それは私が最も不快なことであり、どのように取り除くのか完全には不明です。 – schmidlop

+0

さて、あなたが提供したリンクを読んだので、私はDIコンテナ(Ninject)がこのシナリオに対して何らかの答えを持っていると合理的に予想しなければならないと結論付けました。さらに、それはそうで、私はコンテキストバインディングhttps://github.com/ninject/ninject/wiki/Contextual-Bindingを必要としており、おそらくこれも必要です:https://github.com/ninject/ninject.extensions。工場/ウィキ – schmidlop

+0

ええ、それはあなたの問題を実際に解決するはずです。あなたの初期設定では、リソースファイルからロードできるはずです。 –

関連する問題