2016-05-12 15 views
1

Ich habe eine SchnittstelleInject erfordern Objekt unter der Bedingung in Konstruktor Injektion hängt

public interface ITrnsitReport 
{ 
    List<UserDefinedType> GetTransitReportData(); 
} 

Und es hat nur eine Implementierung, die

public class TransitReport : ITrnsitReport 
{ 
    private IValidateInput _inputValidation = null; 
    private readonly ITransitRepository _transitRepo = null; 
    public TransitReport (IValidateInput inputValidation, 
          ITransitRepository transitRepo) 
    { 
     _inputValidation = inputValidation; 
     _transitRepo = transitRepo; 
    } 
    public List<UserDefinedType> GetTransitReportData (string input1, string input2) 
    { 
     List<UserDefinedType> ppdcReportList = null; 
     bool isValid = _inputValidation.IsInputValid (input1, input2); 
     if (isValid) 
     { 
      ppdcReportList = _transitRepo.GetTransitData (input1, input2); 
      // do something with data 
     } 
     return ppdcReportList; 
    } 
} 

ist nun IValidateInput zwei Implementierungen wie PPDCValidateInput und PAIValidateInput hat. Wieder für ITransitRepository wie PPDCTransitRepository und PAITransitRepository. (wo PAI und PPDC Geschäftsberichte sind und jeder über eine andere Validierung und ein anderes Repository verfügt)

Ich verwende Unity Framework und lasse sie unter UnityConfig.cs registrieren.

New ich zu tun versuchen, ist

public TransitInfo : ITransitInfo 
{ 
    private ITrnsitReport _report = null; 
    public TransitInfo (ITrnsitReport report) 
    { 
     _report = report; 
    } 
    public List<UserDefinedType> GetReportData (string reportType, string input1, string input2) 
    { 
     if (reportType.Equals ("PAI")) 
     { 
      _report.GetTransitReportData (input1, input2); //inject PAIValidateInput and PAITransitRepository objects 
     } 
     if else (reportType.Equals ("PPDC")) 
     { 
      _report.GetTransitReportData (input1, input2); //inject PPDCValidateInput and PPDCTransitRepository objects 
     } 
    } 
} 

Wenn seine „PAI“ Wie kann ich PAIValidateInput und PAITransitRepository Objekte TransitReport Konstruktor und für „PPDC“ PPDCValidateInput und PPDCTransitRepository Objekte injizieren.

Antwort

3

Es gibt mehrere Möglichkeiten.

1. Verwenden genannt Registrierungen.

container.RegisterType<IValidateInput, PPDCValidateInput>("PPDC"); 

container.RegisterType<IValidateInput, PAIValidateInput>("PAI"); 

Und in Ihrem Konstruktor:

public TransitReport ([Dependency("PPDC")]IValidateInput inputValidation, 
         ITransitRepository transitRepo) 
{ 
    _inputValidation = inputValidation; 
    _transitRepo = transitRepo; 
} 

Oder in Ihrer Registrierung:

container.Register<ITrnsitReport>(new InjectionConstructor(new ResolvedParameter<IValidateInput>("PPDC")); 

Der Nachteil bei diesem Ansatz ist, dass der Verbraucher der Schnittstelle, die Umsetzung der wissen muss, Schnittstelle, die es will, die die ganze Idéa des Einspritzens einer Schnittstelle in erster Linie bricht.


2. Verwenden Sie eine Enum zu definieren, was es zu validieren.

public interface ITrnsitReport 
{ 
    List<UserDefinedType> GetTransitReportData(); 
    ValidateType ValidateType { get; } 
} 

public enum ValidateType 
{ 
    PPDC = 1, 
    PAI = 2 
} 

Und dann wählen Sie es aus, wenn Sie es verwenden möchten.

public TransitReport (IValidateInput[] inputValidation, 
         ITransitRepository transitRepo) 
{ 
    _inputValidation = inputValidation.FirstOrDefault(x => x.ValidateType == ValidateType.PPC); 
    _transitRepo = transitRepo; 
} 

Der gute Teil ist, dass die Logik innerhalb der Schnittstelle selbst ist, und nicht in Bezug auf die Registrierung. Es erfordert jedoch immer noch, dass der Verbraucher der Schnittstelle weiß, was er will.


3. Verwenden Sie verschiedene Schnittstellen.(Wahrscheinlich die beste Option in meiner Meinung nach)

public interface IPAIValidateInput : IValidateInput 
{ 

} 

public interface IPPDCValidateInput : IValidateInput 
{ 

} 

Und dann registrieren sie separat in Ihrem Container und injizieren Sie die Schnittstelle, die Sie eigentlich wollen.

public TransitReport (IPAIValidateInput inputValidation, 
         ITransitRepository transitRepo) 
{ 
    _inputValidation = inputValidation; 
    _transitRepo = transitRepo; 
} 

Erfordert Schnittstellen ohne tatsächliche Deklaration. Aber es hält die DI-Logik in meiner Meinung reiner.


4. Verwenden eine Basisklasse und kombinieren sie alle.

Erste fix genannt Anmeldungen:

container.RegisterType<IValidateInput, PPDCValidateInput>("PPDC"); 
container.RegisterType<IValidateInput, PAIValidateInput>("PAI"); 
container.RegisterType<ITransitRepository, PPDCTransitRepository>("PPDC"); 
container.RegisterType<ITransitRepository, PAITransitRepository>("PAI"); 
container.RegisterType<ITransitReport, PAITransitReport>("PAI"); 
container.RegisterType<ITransitReport, PPDCTransitReport>("PPDC"); 

Dann eine Basisklasse erstellen

public abstract class TransitReportBase : ITrnsitReport 
{ 
    private readonly IValidateInput _inputValidation; 
    private readonly ITransitRepository _transitRepo; 

    protected TransitReportBase(IValidateInput inputValidation, 
          ITransitRepository transitRepo) 
    { 
     _inputValidation = inputValidation; 
     _transitRepo = transitRepo; 
    } 

    public List<UserDefinedType> GetTransitReportData(string input1, string input2) 
    { 
     List<UserDefinedType> ppdcReportList = null; 
     bool isValid = _inputValidation.IsInputValid(input1, input2); 
     if (isValid) 
     { 
      ppdcReportList = _transitRepo.GetTransitData(input1, input2); 
      // do something with data 
     } 
     return ppdcReportList; 
    } 
} 

public class PAITransitReport : TransitReportBase 
{ 

    public PAITransitReport([Dependency("PAI")] IValidateInput inputValidation, 
          [Dependency("PAI")] ITransitRepository transitRepo) : base(inputValidation, transitRepo) 
    { 

    } 
} 

public class PPDCTransitReport : TransitReportBase 
{ 
    public PPDCTransitReport([Dependency("PPDC")] IValidateInput inputValidation, 
          [Dependency("PPDC")] ITransitRepository transitRepo) : base(inputValidation, transitRepo) 
    { 

    } 
} 

und eine Fabrik, um sie zu lösen:

public class TransitReportFactory : ITransitReportFactory 
{ 
    private readonly IUnityContainer _container; 

    public TransitReportFactory(IUnityContainer container) // container is injected automatically. 
    { 
     _container = container; 
    } 

    ITrnsitReport Create(string reportType) 
    { 
     return _container.Resolve<ITrnsitReport>(reportType); 
    } 
} 

Dank der konkreten Klassen PPDCTransitReport und PAITransitReport können wir sicherstellen, dass die richtige Abhängigkeit inje ist der Basisklasse.

Wie die Fabrik verwenden:

Zuerst registriert es mit Unity.

container.RegisterType<ITransitReportFactory, TransitReportFactory>(); 

Dann spritzen Sie es in Ihre TransitInfo.

public TransitInfo : ITransitInfo 
{ 
    private ITransitReportFactory _transitReportFactory; 
    public TransitInfo (ITransitReportFactory transitReportFactory) 
    { 
     _transitReportFactory = transitReportFactory; 
    } 
    public List<UserDefinedType> GetReportData (string reportType, string input1, string input2) 
    { 
     // Create your transitreport object. 
     ITransitReport report = _transitReportFactory.Create(reportType); 
     var reportData = report.GetTransitReportData (input1, input2); 
     return reportData; 
    } 
} 

Aber ich muss sagen, dass die Fabrik selbst nicht so viel zur Lösung hinzufügen. Wenn Sie das Service Locator-Muster nicht stören, können Sie IUnityContainer direkt zu TransitInfo injizieren.

+0

Entschuldigung für die Frage, aber ich bin etwas verwirrend über die Fabrik, wie übergebe ich den 'IUnityContainer' Typ und wo' Create' Methode aufrufen. – Riki

+0

Sie hatten Recht zu fragen. Es war überhaupt nicht offensichtlich. Ich habe die Antwort angepasst. – smoksnes

0

Sie haben mehrere Möglichkeiten, die ich lieber mit dem Namen Registrierungen verwenden:

container.RegisterType<IValidateInput, PPDCValidateInput>("PPDC");   
container.RegisterType<IValidateInput, PAIValidateInput>("PAI"); 

Dann müssen Sie die ITransitInfo mit Überschreibungen beheben: gehen

container.Resolve<ITransitInfo>(new InjectionConstructor(new ResolvedParameter<IValidateInput>("PPDC"), ...)