MEF 中的设计模式策略

Design pattern strategy in MEF

我有 returns 对象实现特定接口的方法。取决于参数方法 return 不同的对象。全部实现相同的接口,因此我可以在方法外部的接口上使用相同的方法,如 Execute()。 这个解决方案迫使我避免使用 MEF。如何同时使用这两种解决方案?从 MEF 导入构造函数并在单独的 classes?

中隔离不同的策略

这是一个示例代码:

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

下面是方法的使用

    [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();
        }
        //(...)
    }  

总结: 我喜欢将不同的策略分离到不同的 class,这里是 UkCrowdMessageProcessorDefaultCrowdMessageProcessorAdapter。但是在新的这种 class (ICrowdMessageProcessor) 中,我还需要使用 ImportingConstructor。我该怎么做?

解决方案一: 使用 CompositionContainer 及其方法 GetExportedValue。 当它看起来时:

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

解决方案 2:使用 ServiceLocatorGetInstance

解决方案 3:从设计的角度来看,这是唯一正确的解决方案。

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