6

제 질문의 핵심은 MVC3과 Ninject를 사용하여 이러한 객체를 구성하는 방법입니다 (아래 참조).하지만 DI가 솔루션에서 역할을해야하는지는 확실하지 않지만). 내 프로젝트의 실제 세부 사항을 공개 할 수는 없지만 여기에 문제/질문을 보여주는 근사치가 있습니다. VB 또는 C# 중 답변을 주시면 감사하겠습니다!ASP.NET MVC3 프로젝트에서 다형성 객체 작성하기

나는 다양한 속성을 지닌 여러 제품을 가지고 있지만 모두 카탈로그로 나타내야합니다. 각 제품 클래스에는 내 데이터베이스에 해당 테이블이 있습니다. 카탈로그 엔트리는 카탈로그 엔트리에 고유 한 소수의 특성을 가지므로 결과적으로 자체 테이블을 갖습니다. 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 

는 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 

어딘가에과 같은 코드가있을 것이다 : 뷰에서
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 및/또는 generics가 이것을 더 잘 할 수 있다고 말합니다. 이 문제를 처리하는 방법에 대한 제안은 많은 도움이됩니다. (더 나은 제목에 대한 제안과 같이)

답변

1

그래서 약간의 변경을 가하면 Ninject Factory 확장을 사용하여 작업 할 수 있습니다. 가장 큰 변화는 항목에 실제로 옷이 있고 패스너 특정 속성이 null이고 반대의 경우 해당 유형 (옷을 입은 것 또는 고의적으로 만든 패스너)을 표시 할 수있는 충분한 정보가 있다는 것입니다. 다음과 같이

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은 다음과 같이이다 :

그것은이를 알아 내기 위해 나에게 가장 도움이 this post했다
Public Class ClothingCatalogEntry 
    Public Sub New(ByVal entity As CatalogEntryEntity) 
... 

. 거기에 표시된대로 정확히 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 설치 코드가 일부 파일에 있습니다. 이렇게하면 여러 메소드/컨트롤러가 아닌 한 위치에 전환 코드 만 있습니다. 당신은 의존성 주입을 사용하는 custom resolver을 가지고 있습니다 (() => new CustomResolver() 대신에) 이것은 디스플레이 텍스트를 얻기위한 논리를 저장합니다.

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

그래, 그게 실제로 문제를 해결해야 해. ninject 초기화에서 리소스 파일에서로드 할 수 있어야합니다. –

관련 문제