I have method what returns objects implementing particular interface. Depends on argument method return different object. All implement the same interface so I can use the same method like Execute() on interface outside the method. This solution force me to avoid of using MEF. How can I use both solution at once? Importing constructor from MEF and isolation of different strategies in separate classes?
Here is an example code:
[Export(typeof(ICrowdMessageProcessorFactory))]
public class CrowdMessageProcessorFactory : ICrowdMessageProcessorFactory
{
private readonly IDefaultCrowdRequestAnalyzer _defaultProcessor;
[ImportingConstructor]
public CrowdMessageProcessorFactory(IDefaultCrowdRequestAnalyzer defaultProcessor)
{
_defaultProcessor = defaultProcessor;
}
public Metadata PayloadMetadata { get; private set; }
public ICrowdMessageProcessor Create(InsertCrowdsourcingEventRequest request, DateTime fireUtcDateTime)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
PayloadMetadata = Metadata.Create(request);
var marketRegion = PayloadMetadata?.GetMarketRegion();
switch (marketRegion)
{
case MarketRegion.Uk:
return new UkCrowdMessageProcessor();
}
return new DefaultCrowdMessageProcessorAdapter(request, fireUtcDateTime, _defaultProcessor);
}
}
And here is use of the method
[ImportingConstructor]
public CrowdResponseAnalyzer(
ICrowdMessageProcessorFactory processorFactory)
{
_processorFactory = processorFactory;
}
public void Execute(InsertCrowdsourcingEventRequest request, DateTime fireUtcDateTime)
{
Guard.ArgumentNotNull(request, "request");
try
{
ICrowdMessageProcessor processor = _processorFactory.Create(request, fireUtcDateTime);
processor.Execute();
}
//(...)
}
In summary: I like to separate different strategies to different class, here in UkCrowdMessageProcessor and DefaultCrowdMessageProcessorAdapter. But in new this kind of class (ICrowdMessageProcessor) i need to use ImportingConstructor also. How can I do it?
Solution 1: Use CompositionContainer and it method GetExportedValue. when it looks:
public ICrowdMessageProcessor Create(InsertCrowdsourcingEventRequest request, DateTime fireUtcDateTime)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
PayloadMetadata = Metadata.Create(request);
var marketRegion = PayloadMetadata?.GetMarketRegion();
switch (marketRegion)
{
case MarketRegion.Uk:
return _cc.GetExportedValue<UkCrowdMessageProcessor>();
}
return PrepareDefaultCrowdMessageProcessor(request, fireUtcDateTime);
}
private ICrowdMessageProcessor PrepareDefaultCrowdMessageProcessor(InsertCrowdsourcingEventRequest request, DateTime fireUtcDateTime)
{
var processor = _cc.GetExportedValue<DefaultCrowdMessageProcessorAdapter>();
processor.Initialize(request, fireUtcDateTime, _defaultProcessor);
return processor;
}
Solution 2: Use ServiceLocator and GetInstance
Solution 3: This one is the only one right from design point of view.
[Export(typeof(ICrowdMessageProcessorFactory))]
public class CrowdMessageProcessorFactory : ICrowdMessageProcessorFactory
{
private readonly IDefaultCrowdRequestAnalyzer _defaultProcessor;
private readonly UkCrowdMessageProcessor _ukCrowdMessageProcessor;
private readonly DefaultCrowdMessageProcessorAdapter _defaultCrowdMessageProcessor;
[ImportingConstructor]
public CrowdMessageProcessorFactory(
IDefaultCrowdRequestAnalyzer defaultProcessor,
UkCrowdMessageProcessor ukCrowdMessageProcessor,
DefaultCrowdMessageProcessorAdapter defaultCrowdMessageProcessor)
{
_defaultProcessor = defaultProcessor;
_ukCrowdMessageProcessor = ukCrowdMessageProcessor;
_defaultCrowdMessageProcessor = defaultCrowdMessageProcessor;
}
public Metadata PayloadMetadata { get; private set; }
public ICrowdMessageProcessor Create(InsertCrowdsourcingEventRequest request, DateTime fireUtcDateTime)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
PayloadMetadata = Metadata.Create(request);
var marketRegion = PayloadMetadata?.GetMarketRegion();
switch (marketRegion)
{
case MarketRegion.Uk:
return _ukCrowdMessageProcessor;
}
return PrepareDefaultCrowdMessageProcessor(request, fireUtcDateTime);
}
private ICrowdMessageProcessor PrepareDefaultCrowdMessageProcessor(InsertCrowdsourcingEventRequest request, DateTime fireUtcDateTime)
{
_defaultCrowdMessageProcessor.Initialize(request, fireUtcDateTime, _defaultProcessor);
return _defaultCrowdMessageProcessor;
}
}