【问题标题】:Design pattern strategy in MEFMEF 中的设计模式策略
【发布时间】:2015-10-07 14:59:57
【问题描述】:

我有方法返回实现特定接口的对象。取决于参数方法返回不同的对象。都实现了相同的接口,所以我可以在方法外的接口上使用相同的方法,如 Execute()。 这个解决方案迫使我避免使用 MEF。如何同时使用这两种解决方案?从 MEF 导入构造函数并在不同的类中隔离不同的策略?

这是一个示例代码:

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

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

【问题讨论】:

  • 您目前如何决定返回哪个对象?也许分享你的代码?
  • 请您将您的解决方案转化为答案。这使它更清晰,并帮助其他可能有同样问题的人。谢谢

标签: .net design-patterns mef


【解决方案1】:

解决方案 1: 使用 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;
    }
}

【讨论】: